PTdecode/CImg-1.3.0/CImg.h

Wed, 05 Aug 2009 15:00:54 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Wed, 05 Aug 2009 15:00:54 +0100
changeset 12
96e1df9bd27c
parent 5
1204ebf9340d
permissions
-rwxr-xr-x

small changes to hexdump code to stop a gcc warning on platforms where sizeof(int) != sizeof(int*) e.g. x86_64

philpem@5 1 /*
philpem@5 2 #
philpem@5 3 # File : CImg.h
philpem@5 4 # ( C++ header file )
philpem@5 5 #
philpem@5 6 # Description : The C++ Template Image Processing Library.
philpem@5 7 # This file is the main part of the CImg Library project.
philpem@5 8 # ( http://cimg.sourceforge.net )
philpem@5 9 #
philpem@5 10 # Project manager : David Tschumperle.
philpem@5 11 # ( http://www.greyc.ensicaen.fr/~dtschump/ )
philpem@5 12 #
philpem@5 13 # The complete contributor list can be seen in the 'README.txt' file.
philpem@5 14 #
philpem@5 15 # Licenses : This file is "dual-licensed", you have to choose one
philpem@5 16 # of the two licenses below to apply on this file.
philpem@5 17 #
philpem@5 18 # CeCILL-C
philpem@5 19 # The CeCILL-C license is close to the GNU LGPL.
philpem@5 20 # ( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
philpem@5 21 #
philpem@5 22 # or CeCILL v2.0
philpem@5 23 # The CeCILL license is compatible with the GNU GPL.
philpem@5 24 # ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
philpem@5 25 #
philpem@5 26 # This software is governed either by the CeCILL or the CeCILL-C license
philpem@5 27 # under French law and abiding by the rules of distribution of free software.
philpem@5 28 # You can use, modify and or redistribute the software under the terms of
philpem@5 29 # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA
philpem@5 30 # at the following URL : "http://www.cecill.info".
philpem@5 31 #
philpem@5 32 # As a counterpart to the access to the source code and rights to copy,
philpem@5 33 # modify and redistribute granted by the license, users are provided only
philpem@5 34 # with a limited warranty and the software's author, the holder of the
philpem@5 35 # economic rights, and the successive licensors have only limited
philpem@5 36 # liability.
philpem@5 37 #
philpem@5 38 # In this respect, the user's attention is drawn to the risks associated
philpem@5 39 # with loading, using, modifying and/or developing or reproducing the
philpem@5 40 # software by the user in light of its specific status of free software,
philpem@5 41 # that may mean that it is complicated to manipulate, and that also
philpem@5 42 # therefore means that it is reserved for developers and experienced
philpem@5 43 # professionals having in-depth computer knowledge. Users are therefore
philpem@5 44 # encouraged to load and test the software's suitability as regards their
philpem@5 45 # requirements in conditions enabling the security of their systems and/or
philpem@5 46 # data to be ensured and, more generally, to use and operate it in the
philpem@5 47 # same conditions as regards security.
philpem@5 48 #
philpem@5 49 # The fact that you are presently reading this means that you have had
philpem@5 50 # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms.
philpem@5 51 #
philpem@5 52 */
philpem@5 53
philpem@5 54 // Define version number of the current file.
philpem@5 55 //
philpem@5 56 #ifndef cimg_version
philpem@5 57 #define cimg_version 130
philpem@5 58
philpem@5 59 /*-----------------------------------------------------------
philpem@5 60 #
philpem@5 61 # Test/auto-set CImg configuration variables
philpem@5 62 # and include required headers.
philpem@5 63 #
philpem@5 64 # If you find that default configuration variables are
philpem@5 65 # not adapted, you can override their values before including
philpem@5 66 # the header file "CImg.h" (using the #define directive).
philpem@5 67 #
philpem@5 68 ------------------------------------------------------------*/
philpem@5 69
philpem@5 70 // Include required standard C++ headers.
philpem@5 71 //
philpem@5 72 #include <cstdio>
philpem@5 73 #include <cstdlib>
philpem@5 74 #include <cstdarg>
philpem@5 75 #include <cstring>
philpem@5 76 #include <cmath>
philpem@5 77 #include <ctime>
philpem@5 78
philpem@5 79 // Operating system configuration.
philpem@5 80 //
philpem@5 81 // Define 'cimg_OS' to : 0 for an unknown OS (will try to minize library dependancies).
philpem@5 82 // 1 for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...).
philpem@5 83 // 2 for Microsoft Windows.
philpem@5 84 //
philpem@5 85 #ifndef cimg_OS
philpem@5 86 #if defined(unix) || defined(__unix) || defined(__unix__) \
philpem@5 87 || defined(linux) || defined(__linux) || defined(__linux__) \
philpem@5 88 || defined(sun) || defined(__sun) \
philpem@5 89 || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
philpem@5 90 || defined(__FreeBSD__) || defined __DragonFly__ \
philpem@5 91 || defined(sgi) || defined(__sgi) \
philpem@5 92 || defined(__MACOSX__) || defined(__APPLE__) \
philpem@5 93 || defined(__CYGWIN__)
philpem@5 94 #define cimg_OS 1
philpem@5 95 #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
philpem@5 96 || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
philpem@5 97 #define cimg_OS 2
philpem@5 98 #else
philpem@5 99 #define cimg_OS 0
philpem@5 100 #endif
philpem@5 101 #elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2)
philpem@5 102 #error CImg Library : Configuration variable 'cimg_OS' is badly defined.
philpem@5 103 #error (valid values are '0=unknown OS', '1=Unix-like OS', '2=Microsoft Windows').
philpem@5 104 #endif
philpem@5 105
philpem@5 106 // Compiler configuration.
philpem@5 107 //
philpem@5 108 // Try to detect Microsoft VC++ compilers.
philpem@5 109 // (lot of workarounds are needed afterwards to
philpem@5 110 // make CImg working, particularly with VC++ 6.0).
philpem@5 111 //
philpem@5 112 #ifdef _MSC_VER
philpem@5 113 #pragma warning(push)
philpem@5 114 #pragma warning(disable:4311)
philpem@5 115 #pragma warning(disable:4312)
philpem@5 116 #pragma warning(disable:4800)
philpem@5 117 #pragma warning(disable:4804)
philpem@5 118 #pragma warning(disable:4996)
philpem@5 119 #define _CRT_SECURE_NO_DEPRECATE 1
philpem@5 120 #define _CRT_NONSTDC_NO_DEPRECATE 1
philpem@5 121 #if _MSC_VER<1300
philpem@5 122 #define cimg_use_visualcpp6
philpem@5 123 #define cimg_std
philpem@5 124 #define _WIN32_WINNT 0x0500
philpem@5 125 #endif
philpem@5 126 #endif
philpem@5 127
philpem@5 128 // Include OS-specific headers.
philpem@5 129 //
philpem@5 130 #if cimg_OS==1
philpem@5 131 #include <sys/time.h>
philpem@5 132 #include <unistd.h>
philpem@5 133 #elif cimg_OS==2
philpem@5 134 #include <windows.h>
philpem@5 135 #ifndef _WIN32_IE
philpem@5 136 #define _WIN32_IE 0x0400
philpem@5 137 #endif
philpem@5 138 #include <shlobj.h>
philpem@5 139 #endif
philpem@5 140
philpem@5 141 // Define defaut pipe for output messages
philpem@5 142 //
philpem@5 143 // Define 'cimg_stdout' to : stdout to print CImg messages on the standard output.
philpem@5 144 // stderr to print CImg messages on the standart error output (default behavior).
philpem@5 145 //
philpem@5 146 #ifndef cimg_std
philpem@5 147 #define cimg_std std
philpem@5 148 #endif
philpem@5 149 #ifndef cimg_stdout
philpem@5 150 #define cimg_stdout stderr
philpem@5 151 #endif
philpem@5 152
philpem@5 153 // Output messages configuration.
philpem@5 154 //
philpem@5 155 // Define 'cimg_debug' to : 0 to hide debug messages (quiet mode, but exceptions are still thrown).
philpem@5 156 // 1 to display debug messages on the console.
philpem@5 157 // 2 to display debug messages with dialog windows (default behavior).
philpem@5 158 // 3 to do as 1 + add extra warnings (may slow down the code !).
philpem@5 159 // 4 to do as 2 + add extra warnings (may slow down the code !).
philpem@5 160 //
philpem@5 161 // Define 'cimg_strict_warnings' to replace warning messages by exception throwns.
philpem@5 162 //
philpem@5 163 // Define 'cimg_use_vt100' to allow output of color messages (require VT100-compatible terminal).
philpem@5 164 //
philpem@5 165 #ifndef cimg_debug
philpem@5 166 #define cimg_debug 2
philpem@5 167 #elif !(cimg_debug==0 || cimg_debug==1 || cimg_debug==2 || cimg_debug==3 || cimg_debug==4)
philpem@5 168 #error CImg Library : Configuration variable 'cimg_debug' is badly defined.
philpem@5 169 #error (valid values are '0=quiet', '1=console', '2=dialog', '3=console+warnings', '4=dialog+warnings').
philpem@5 170 #endif
philpem@5 171
philpem@5 172 // Display framework configuration.
philpem@5 173 //
philpem@5 174 // Define 'cimg_display' to : 0 to disable display capabilities.
philpem@5 175 // 1 to use X-Window framework (X11).
philpem@5 176 // 2 to use Microsoft GDI32 framework.
philpem@5 177 // 3 to use Apple Carbon framework.
philpem@5 178 //
philpem@5 179 #ifndef cimg_display
philpem@5 180 #if cimg_OS==0
philpem@5 181 #define cimg_display 0
philpem@5 182 #elif cimg_OS==1
philpem@5 183 #if defined(__MACOSX__) || defined(__APPLE__)
philpem@5 184 #define cimg_display 1
philpem@5 185 #else
philpem@5 186 #define cimg_display 1
philpem@5 187 #endif
philpem@5 188 #elif cimg_OS==2
philpem@5 189 #define cimg_display 2
philpem@5 190 #endif
philpem@5 191 #elif !(cimg_display==0 || cimg_display==1 || cimg_display==2 || cimg_display==3)
philpem@5 192 #error CImg Library : Configuration variable 'cimg_display' is badly defined.
philpem@5 193 #error (valid values are '0=disable', '1=X-Window (X11)', '2=Microsoft GDI32', '3=Apple Carbon').
philpem@5 194 #endif
philpem@5 195
philpem@5 196 // Include display-specific headers.
philpem@5 197 //
philpem@5 198 #if cimg_display==1
philpem@5 199 #include <X11/Xlib.h>
philpem@5 200 #include <X11/Xutil.h>
philpem@5 201 #include <X11/keysym.h>
philpem@5 202 #include <pthread.h>
philpem@5 203 #ifdef cimg_use_xshm
philpem@5 204 #include <sys/ipc.h>
philpem@5 205 #include <sys/shm.h>
philpem@5 206 #include <X11/extensions/XShm.h>
philpem@5 207 #endif
philpem@5 208 #ifdef cimg_use_xrandr
philpem@5 209 #include <X11/extensions/Xrandr.h>
philpem@5 210 #endif
philpem@5 211 #elif cimg_display==3
philpem@5 212 #include <Carbon/Carbon.h>
philpem@5 213 #include <pthread.h>
philpem@5 214 #endif
philpem@5 215
philpem@5 216 // OpenMP configuration.
philpem@5 217 // (http://www.openmp.org)
philpem@5 218 //
philpem@5 219 // Define 'cimg_use_openmp' to enable OpenMP support.
philpem@5 220 //
philpem@5 221 // OpenMP directives can be used in few CImg functions to get
philpem@5 222 // advantages of multi-core CPUs. Using OpenMP is not mandatory.
philpem@5 223 //
philpem@5 224 #ifdef cimg_use_openmp
philpem@5 225 #include "omp.h"
philpem@5 226 #endif
philpem@5 227
philpem@5 228 // LibPNG configuration.
philpem@5 229 // (http://www.libpng.org)
philpem@5 230 //
philpem@5 231 // Define 'cimg_use_png' to enable LibPNG support.
philpem@5 232 //
philpem@5 233 // LibPNG can be used in functions 'CImg<T>::{load,save}_png()'
philpem@5 234 // to get a builtin support of PNG files. Using LibPNG is not mandatory.
philpem@5 235 //
philpem@5 236 #ifdef cimg_use_png
philpem@5 237 extern "C" {
philpem@5 238 #include "png.h"
philpem@5 239 }
philpem@5 240 #endif
philpem@5 241
philpem@5 242 // LibJPEG configuration.
philpem@5 243 // (http://en.wikipedia.org/wiki/Libjpeg)
philpem@5 244 //
philpem@5 245 // Define 'cimg_use_jpeg' to enable LibJPEG support.
philpem@5 246 //
philpem@5 247 // LibJPEG can be used in functions 'CImg<T>::{load,save}_jpeg()'
philpem@5 248 // to get a builtin support of JPEG files. Using LibJPEG is not mandatory.
philpem@5 249 //
philpem@5 250 #ifdef cimg_use_jpeg
philpem@5 251 extern "C" {
philpem@5 252 #include "jpeglib.h"
philpem@5 253 }
philpem@5 254 #endif
philpem@5 255
philpem@5 256 // LibTIFF configuration.
philpem@5 257 // (http://www.libtiff.org)
philpem@5 258 //
philpem@5 259 // Define 'cimg_use_tiff' to enable LibTIFF support.
philpem@5 260 //
philpem@5 261 // LibTIFF can be used in functions 'CImg[List]<T>::{load,save}_tiff()'
philpem@5 262 // to get a builtin support of TIFF files. Using LibTIFF is not mandatory.
philpem@5 263 //
philpem@5 264 #ifdef cimg_use_tiff
philpem@5 265 extern "C" {
philpem@5 266 #include "tiffio.h"
philpem@5 267 }
philpem@5 268 #endif
philpem@5 269
philpem@5 270 // FFMPEG Avcodec and Avformat libraries configuration.
philpem@5 271 // (http://www.ffmpeg.org)
philpem@5 272 //
philpem@5 273 // Define 'cimg_use_ffmpeg' to enable FFMPEG lib support.
philpem@5 274 //
philpem@5 275 // Avcodec and Avformat libraries can be used in functions
philpem@5 276 // 'CImg[List]<T>::load_ffmpeg()' to get a builtin
philpem@5 277 // support of various image sequences files.
philpem@5 278 // Using FFMPEG libraries is not mandatory.
philpem@5 279 //
philpem@5 280 #ifdef cimg_use_ffmpeg
philpem@5 281 extern "C" {
philpem@5 282 #include "avformat.h"
philpem@5 283 #include "avcodec.h"
philpem@5 284 #include "swscale.h"
philpem@5 285 }
philpem@5 286 #endif
philpem@5 287
philpem@5 288 // Zlib configuration
philpem@5 289 // (http://www.zlib.net)
philpem@5 290 //
philpem@5 291 // Define 'cimg_use_zlib' to enable Zlib support.
philpem@5 292 //
philpem@5 293 // Zlib can be used in functions 'CImg[List]<T>::{load,save}_cimg()'
philpem@5 294 // to allow compressed data in '.cimg' files. Using Zlib is not mandatory.
philpem@5 295 //
philpem@5 296 #ifdef cimg_use_zlib
philpem@5 297 extern "C" {
philpem@5 298 #include "zlib.h"
philpem@5 299 }
philpem@5 300 #endif
philpem@5 301
philpem@5 302 // Magick++ configuration.
philpem@5 303 // (http://www.imagemagick.org/Magick++)
philpem@5 304 //
philpem@5 305 // Define 'cimg_use_magick' to enable Magick++ support.
philpem@5 306 //
philpem@5 307 // Magick++ library can be used in functions 'CImg<T>::{load,save}()'
philpem@5 308 // to get a builtin support of various image formats (PNG,JPEG,TIFF,...).
philpem@5 309 // Using Magick++ is not mandatory.
philpem@5 310 //
philpem@5 311 #ifdef cimg_use_magick
philpem@5 312 #include "Magick++.h"
philpem@5 313 #endif
philpem@5 314
philpem@5 315 // FFTW3 configuration.
philpem@5 316 // (http://www.fftw.org)
philpem@5 317 //
philpem@5 318 // Define 'cimg_use_fftw3' to enable libFFTW3 support.
philpem@5 319 //
philpem@5 320 // FFTW3 library can be used in functions 'CImg[List]<T>::FFT()' to
philpem@5 321 // efficiently compile the Fast Fourier Transform of image data.
philpem@5 322 //
philpem@5 323 #ifdef cimg_use_fftw3
philpem@5 324 extern "C" {
philpem@5 325 #include "fftw3.h"
philpem@5 326 }
philpem@5 327 #endif
philpem@5 328
philpem@5 329 // Board configuration.
philpem@5 330 // (http://libboard.sourceforge.net/)
philpem@5 331 //
philpem@5 332 // Define 'cimg_use_board' to enable Board support.
philpem@5 333 //
philpem@5 334 // Board library can be used in functions 'CImg<T>::draw_object3d()'
philpem@5 335 // to draw objects 3D in vector-graphics canvas that can be saved
philpem@5 336 // as .PS or .SVG files afterwards.
philpem@5 337 //
philpem@5 338 #ifdef cimg_use_board
philpem@5 339 #include "Board.h"
philpem@5 340 #endif
philpem@5 341
philpem@5 342 // Lapack configuration.
philpem@5 343 // (http://www.netlib.org/lapack)
philpem@5 344 //
philpem@5 345 // Define 'cimg_use_lapack' to enable LAPACK support.
philpem@5 346 //
philpem@5 347 // Lapack can be used in various CImg functions dealing with
philpem@5 348 // matrix computation and algorithms (eigenvalues, inverse, ...).
philpem@5 349 // Using Lapack is not mandatory.
philpem@5 350 //
philpem@5 351 #ifdef cimg_use_lapack
philpem@5 352 extern "C" {
philpem@5 353 extern void sgetrf_(int*, int*, float*, int*, int*, int*);
philpem@5 354 extern void sgetri_(int*, float*, int*, int*, float*, int*, int*);
philpem@5 355 extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*);
philpem@5 356 extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*);
philpem@5 357 extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*);
philpem@5 358 extern void dgetrf_(int*, int*, double*, int*, int*, int*);
philpem@5 359 extern void dgetri_(int*, double*, int*, int*, double*, int*, int*);
philpem@5 360 extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*);
philpem@5 361 extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, int*, double*, int*, double*, int*, int*);
philpem@5 362 extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*);
philpem@5 363 }
philpem@5 364 #endif
philpem@5 365
philpem@5 366 // Check if min/max macros are defined.
philpem@5 367 //
philpem@5 368 // CImg does not compile if macros 'min' or 'max' are defined,
philpem@5 369 // because min() and max() functions are also defined in the cimg:: namespace.
philpem@5 370 // so it '#undef' these macros if necessary, and restore them to reasonable
philpem@5 371 // values at the end of the file.
philpem@5 372 //
philpem@5 373 #ifdef min
philpem@5 374 #undef min
philpem@5 375 #define _cimg_redefine_min
philpem@5 376 #endif
philpem@5 377 #ifdef max
philpem@5 378 #undef max
philpem@5 379 #define _cimg_redefine_max
philpem@5 380 #endif
philpem@5 381
philpem@5 382 // Set the current working directory for native MacOSX bundled applications.
philpem@5 383 //
philpem@5 384 // By default, MacOS bundled applications set the cwd at the root directory '/',
philpem@5 385 // the code below allows to set it to the current exec directory instead when
philpem@5 386 // a CImg-based program is executed.
philpem@5 387 //
philpem@5 388 #if cimg_OS==1 && cimg_display==3
philpem@5 389 static struct _cimg_macosx_setcwd {
philpem@5 390 _cimg_macosx_setcwd() {
philpem@5 391 FSRef location;
philpem@5 392 ProcessSerialNumber psn;
philpem@5 393 char filePath[512];
philpem@5 394 if (GetCurrentProcess(&psn)!=noErr) return;
philpem@5 395 if (GetProcessBundleLocation(&psn,&location)!=noErr) return;
philpem@5 396 FSRefMakePath(&location,(UInt8*)filePath,sizeof(filePath)-1);
philpem@5 397 int p = cimg_std::strlen(filePath);
philpem@5 398 while (filePath[p] != '/') --p;
philpem@5 399 filePath[p] = 0;
philpem@5 400 chdir(filePath);
philpem@5 401 }
philpem@5 402 } cimg_macosx_setcwd;
philpem@5 403 #endif
philpem@5 404
philpem@5 405 /*------------------------------------------------------------------------------
philpem@5 406 #
philpem@5 407 # Define user-friendly macros.
philpem@5 408 #
philpem@5 409 # User macros are prefixed by 'cimg_' and can be used in your own code.
philpem@5 410 # They are particularly useful for option parsing, and image loops creation.
philpem@5 411 #
philpem@5 412 ------------------------------------------------------------------------------*/
philpem@5 413
philpem@5 414 // Define the program usage, and retrieve command line arguments.
philpem@5 415 //
philpem@5 416 #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage)
philpem@5 417 #define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0)
philpem@5 418 #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage)
philpem@5 419 #define cimg_argument(pos) cimg_library::cimg::argument(pos,argc,argv)
philpem@5 420 #define cimg_argument1(pos,s0) cimg_library::cimg::argument(pos,argc,argv,1,s0)
philpem@5 421 #define cimg_argument2(pos,s0,s1) cimg_library::cimg::argument(pos,argc,argv,2,s0,s1)
philpem@5 422 #define cimg_argument3(pos,s0,s1,s2) cimg_library::cimg::argument(pos,argc,argv,3,s0,s1,s2)
philpem@5 423 #define cimg_argument4(pos,s0,s1,s2,s3) cimg_library::cimg::argument(pos,argc,argv,4,s0,s1,s2,s3)
philpem@5 424 #define cimg_argument5(pos,s0,s1,s2,s3,s4) cimg_library::cimg::argument(pos,argc,argv,5,s0,s1,s2,s3,s4)
philpem@5 425 #define cimg_argument6(pos,s0,s1,s2,s3,s4,s5) cimg_library::cimg::argument(pos,argc,argv,6,s0,s1,s2,s3,s4,s5)
philpem@5 426 #define cimg_argument7(pos,s0,s1,s2,s3,s4,s5,s6) cimg_library::cimg::argument(pos,argc,argv,7,s0,s1,s2,s3,s4,s5,s6)
philpem@5 427 #define cimg_argument8(pos,s0,s1,s2,s3,s4,s5,s6,s7) cimg_library::cimg::argument(pos,argc,argv,8,s0,s1,s2,s3,s4,s5,s6,s7)
philpem@5 428 #define cimg_argument9(pos,s0,s1,s2,s3,s4,s5,s6,s7,s8) cimg_library::cimg::argument(pos,argc,argv,9,s0,s1,s2,s3,s4,s5,s6,s7,s8)
philpem@5 429
philpem@5 430 // Define and manipulate local neighborhoods.
philpem@5 431 //
philpem@5 432 #define CImg_2x2(I,T) T I[4]; \
philpem@5 433 T& I##cc = I[0]; T& I##nc = I[1]; \
philpem@5 434 T& I##cn = I[2]; T& I##nn = I[3]; \
philpem@5 435 I##cc = I##nc = \
philpem@5 436 I##cn = I##nn = 0
philpem@5 437
philpem@5 438 #define CImg_3x3(I,T) T I[9]; \
philpem@5 439 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \
philpem@5 440 T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \
philpem@5 441 T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \
philpem@5 442 I##pp = I##cp = I##np = \
philpem@5 443 I##pc = I##cc = I##nc = \
philpem@5 444 I##pn = I##cn = I##nn = 0
philpem@5 445
philpem@5 446 #define CImg_4x4(I,T) T I[16]; \
philpem@5 447 T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \
philpem@5 448 T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \
philpem@5 449 T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \
philpem@5 450 T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \
philpem@5 451 I##pp = I##cp = I##np = I##ap = \
philpem@5 452 I##pc = I##cc = I##nc = I##ac = \
philpem@5 453 I##pn = I##cn = I##nn = I##an = \
philpem@5 454 I##pa = I##ca = I##na = I##aa = 0
philpem@5 455
philpem@5 456 #define CImg_5x5(I,T) T I[25]; \
philpem@5 457 T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \
philpem@5 458 T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \
philpem@5 459 T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \
philpem@5 460 T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \
philpem@5 461 T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \
philpem@5 462 I##bb = I##pb = I##cb = I##nb = I##ab = \
philpem@5 463 I##bp = I##pp = I##cp = I##np = I##ap = \
philpem@5 464 I##bc = I##pc = I##cc = I##nc = I##ac = \
philpem@5 465 I##bn = I##pn = I##cn = I##nn = I##an = \
philpem@5 466 I##ba = I##pa = I##ca = I##na = I##aa = 0
philpem@5 467
philpem@5 468 #define CImg_2x2x2(I,T) T I[8]; \
philpem@5 469 T& I##ccc = I[0]; T& I##ncc = I[1]; \
philpem@5 470 T& I##cnc = I[2]; T& I##nnc = I[3]; \
philpem@5 471 T& I##ccn = I[4]; T& I##ncn = I[5]; \
philpem@5 472 T& I##cnn = I[6]; T& I##nnn = I[7]; \
philpem@5 473 I##ccc = I##ncc = \
philpem@5 474 I##cnc = I##nnc = \
philpem@5 475 I##ccn = I##ncn = \
philpem@5 476 I##cnn = I##nnn = 0
philpem@5 477
philpem@5 478 #define CImg_3x3x3(I,T) T I[27]; \
philpem@5 479 T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \
philpem@5 480 T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \
philpem@5 481 T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \
philpem@5 482 T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \
philpem@5 483 T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \
philpem@5 484 T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \
philpem@5 485 T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \
philpem@5 486 T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \
philpem@5 487 T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \
philpem@5 488 I##ppp = I##cpp = I##npp = \
philpem@5 489 I##pcp = I##ccp = I##ncp = \
philpem@5 490 I##pnp = I##cnp = I##nnp = \
philpem@5 491 I##ppc = I##cpc = I##npc = \
philpem@5 492 I##pcc = I##ccc = I##ncc = \
philpem@5 493 I##pnc = I##cnc = I##nnc = \
philpem@5 494 I##ppn = I##cpn = I##npn = \
philpem@5 495 I##pcn = I##ccn = I##ncn = \
philpem@5 496 I##pnn = I##cnn = I##nnn = 0
philpem@5 497
philpem@5 498 #define cimg_get2x2(img,x,y,z,v,I) \
philpem@5 499 I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v)
philpem@5 500
philpem@5 501 #define cimg_get3x3(img,x,y,z,v,I) \
philpem@5 502 I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_p1##x,y,z,v), \
philpem@5 503 I[4] = (img)(x,y,z,v), I[5] = (img)(_n1##x,y,z,v), I[6] = (img)(_p1##x,_n1##y,z,v), I[7] = (img)(x,_n1##y,z,v), \
philpem@5 504 I[8] = (img)(_n1##x,_n1##y,z,v)
philpem@5 505
philpem@5 506 #define cimg_get4x4(img,x,y,z,v,I) \
philpem@5 507 I[0] = (img)(_p1##x,_p1##y,z,v), I[1] = (img)(x,_p1##y,z,v), I[2] = (img)(_n1##x,_p1##y,z,v), I[3] = (img)(_n2##x,_p1##y,z,v), \
philpem@5 508 I[4] = (img)(_p1##x,y,z,v), I[5] = (img)(x,y,z,v), I[6] = (img)(_n1##x,y,z,v), I[7] = (img)(_n2##x,y,z,v), \
philpem@5 509 I[8] = (img)(_p1##x,_n1##y,z,v), I[9] = (img)(x,_n1##y,z,v), I[10] = (img)(_n1##x,_n1##y,z,v), I[11] = (img)(_n2##x,_n1##y,z,v), \
philpem@5 510 I[12] = (img)(_p1##x,_n2##y,z,v), I[13] = (img)(x,_n2##y,z,v), I[14] = (img)(_n1##x,_n2##y,z,v), I[15] = (img)(_n2##x,_n2##y,z,v)
philpem@5 511
philpem@5 512 #define cimg_get5x5(img,x,y,z,v,I) \
philpem@5 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), \
philpem@5 514 I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_p2##x,_p1##y,z,v), I[6] = (img)(_p1##x,_p1##y,z,v), I[7] = (img)(x,_p1##y,z,v), \
philpem@5 515 I[8] = (img)(_n1##x,_p1##y,z,v), I[9] = (img)(_n2##x,_p1##y,z,v), I[10] = (img)(_p2##x,y,z,v), I[11] = (img)(_p1##x,y,z,v), \
philpem@5 516 I[12] = (img)(x,y,z,v), I[13] = (img)(_n1##x,y,z,v), I[14] = (img)(_n2##x,y,z,v), I[15] = (img)(_p2##x,_n1##y,z,v), \
philpem@5 517 I[16] = (img)(_p1##x,_n1##y,z,v), I[17] = (img)(x,_n1##y,z,v), I[18] = (img)(_n1##x,_n1##y,z,v), I[19] = (img)(_n2##x,_n1##y,z,v), \
philpem@5 518 I[20] = (img)(_p2##x,_n2##y,z,v), I[21] = (img)(_p1##x,_n2##y,z,v), I[22] = (img)(x,_n2##y,z,v), I[23] = (img)(_n1##x,_n2##y,z,v), \
philpem@5 519 I[24] = (img)(_n2##x,_n2##y,z,v)
philpem@5 520
philpem@5 521 #define cimg_get6x6(img,x,y,z,v,I) \
philpem@5 522 I[0] = (img)(_p2##x,_p2##y,z,v), I[1] = (img)(_p1##x,_p2##y,z,v), I[2] = (img)(x,_p2##y,z,v), I[3] = (img)(_n1##x,_p2##y,z,v), \
philpem@5 523 I[4] = (img)(_n2##x,_p2##y,z,v), I[5] = (img)(_n3##x,_p2##y,z,v), I[6] = (img)(_p2##x,_p1##y,z,v), I[7] = (img)(_p1##x,_p1##y,z,v), \
philpem@5 524 I[8] = (img)(x,_p1##y,z,v), I[9] = (img)(_n1##x,_p1##y,z,v), I[10] = (img)(_n2##x,_p1##y,z,v), I[11] = (img)(_n3##x,_p1##y,z,v), \
philpem@5 525 I[12] = (img)(_p2##x,y,z,v), I[13] = (img)(_p1##x,y,z,v), I[14] = (img)(x,y,z,v), I[15] = (img)(_n1##x,y,z,v), \
philpem@5 526 I[16] = (img)(_n2##x,y,z,v), I[17] = (img)(_n3##x,y,z,v), I[18] = (img)(_p2##x,_n1##y,z,v), I[19] = (img)(_p1##x,_n1##y,z,v), \
philpem@5 527 I[20] = (img)(x,_n1##y,z,v), I[21] = (img)(_n1##x,_n1##y,z,v), I[22] = (img)(_n2##x,_n1##y,z,v), I[23] = (img)(_n3##x,_n1##y,z,v), \
philpem@5 528 I[24] = (img)(_p2##x,_n2##y,z,v), I[25] = (img)(_p1##x,_n2##y,z,v), I[26] = (img)(x,_n2##y,z,v), I[27] = (img)(_n1##x,_n2##y,z,v), \
philpem@5 529 I[28] = (img)(_n2##x,_n2##y,z,v), I[29] = (img)(_n3##x,_n2##y,z,v), I[30] = (img)(_p2##x,_n3##y,z,v), I[31] = (img)(_p1##x,_n3##y,z,v), \
philpem@5 530 I[32] = (img)(x,_n3##y,z,v), I[33] = (img)(_n1##x,_n3##y,z,v), I[34] = (img)(_n2##x,_n3##y,z,v), I[35] = (img)(_n3##x,_n3##y,z,v)
philpem@5 531
philpem@5 532 #define cimg_get7x7(img,x,y,z,v,I) \
philpem@5 533 I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
philpem@5 534 I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_p3##x,_p2##y,z,v), \
philpem@5 535 I[8] = (img)(_p2##x,_p2##y,z,v), I[9] = (img)(_p1##x,_p2##y,z,v), I[10] = (img)(x,_p2##y,z,v), I[11] = (img)(_n1##x,_p2##y,z,v), \
philpem@5 536 I[12] = (img)(_n2##x,_p2##y,z,v), I[13] = (img)(_n3##x,_p2##y,z,v), I[14] = (img)(_p3##x,_p1##y,z,v), I[15] = (img)(_p2##x,_p1##y,z,v), \
philpem@5 537 I[16] = (img)(_p1##x,_p1##y,z,v), I[17] = (img)(x,_p1##y,z,v), I[18] = (img)(_n1##x,_p1##y,z,v), I[19] = (img)(_n2##x,_p1##y,z,v), \
philpem@5 538 I[20] = (img)(_n3##x,_p1##y,z,v), I[21] = (img)(_p3##x,y,z,v), I[22] = (img)(_p2##x,y,z,v), I[23] = (img)(_p1##x,y,z,v), \
philpem@5 539 I[24] = (img)(x,y,z,v), I[25] = (img)(_n1##x,y,z,v), I[26] = (img)(_n2##x,y,z,v), I[27] = (img)(_n3##x,y,z,v), \
philpem@5 540 I[28] = (img)(_p3##x,_n1##y,z,v), I[29] = (img)(_p2##x,_n1##y,z,v), I[30] = (img)(_p1##x,_n1##y,z,v), I[31] = (img)(x,_n1##y,z,v), \
philpem@5 541 I[32] = (img)(_n1##x,_n1##y,z,v), I[33] = (img)(_n2##x,_n1##y,z,v), I[34] = (img)(_n3##x,_n1##y,z,v), I[35] = (img)(_p3##x,_n2##y,z,v), \
philpem@5 542 I[36] = (img)(_p2##x,_n2##y,z,v), I[37] = (img)(_p1##x,_n2##y,z,v), I[38] = (img)(x,_n2##y,z,v), I[39] = (img)(_n1##x,_n2##y,z,v), \
philpem@5 543 I[40] = (img)(_n2##x,_n2##y,z,v), I[41] = (img)(_n3##x,_n2##y,z,v), I[42] = (img)(_p3##x,_n3##y,z,v), I[43] = (img)(_p2##x,_n3##y,z,v), \
philpem@5 544 I[44] = (img)(_p1##x,_n3##y,z,v), I[45] = (img)(x,_n3##y,z,v), I[46] = (img)(_n1##x,_n3##y,z,v), I[47] = (img)(_n2##x,_n3##y,z,v), \
philpem@5 545 I[48] = (img)(_n3##x,_n3##y,z,v)
philpem@5 546
philpem@5 547 #define cimg_get8x8(img,x,y,z,v,I) \
philpem@5 548 I[0] = (img)(_p3##x,_p3##y,z,v), I[1] = (img)(_p2##x,_p3##y,z,v), I[2] = (img)(_p1##x,_p3##y,z,v), I[3] = (img)(x,_p3##y,z,v), \
philpem@5 549 I[4] = (img)(_n1##x,_p3##y,z,v), I[5] = (img)(_n2##x,_p3##y,z,v), I[6] = (img)(_n3##x,_p3##y,z,v), I[7] = (img)(_n4##x,_p3##y,z,v), \
philpem@5 550 I[8] = (img)(_p3##x,_p2##y,z,v), I[9] = (img)(_p2##x,_p2##y,z,v), I[10] = (img)(_p1##x,_p2##y,z,v), I[11] = (img)(x,_p2##y,z,v), \
philpem@5 551 I[12] = (img)(_n1##x,_p2##y,z,v), I[13] = (img)(_n2##x,_p2##y,z,v), I[14] = (img)(_n3##x,_p2##y,z,v), I[15] = (img)(_n4##x,_p2##y,z,v), \
philpem@5 552 I[16] = (img)(_p3##x,_p1##y,z,v), I[17] = (img)(_p2##x,_p1##y,z,v), I[18] = (img)(_p1##x,_p1##y,z,v), I[19] = (img)(x,_p1##y,z,v), \
philpem@5 553 I[20] = (img)(_n1##x,_p1##y,z,v), I[21] = (img)(_n2##x,_p1##y,z,v), I[22] = (img)(_n3##x,_p1##y,z,v), I[23] = (img)(_n4##x,_p1##y,z,v), \
philpem@5 554 I[24] = (img)(_p3##x,y,z,v), I[25] = (img)(_p2##x,y,z,v), I[26] = (img)(_p1##x,y,z,v), I[27] = (img)(x,y,z,v), \
philpem@5 555 I[28] = (img)(_n1##x,y,z,v), I[29] = (img)(_n2##x,y,z,v), I[30] = (img)(_n3##x,y,z,v), I[31] = (img)(_n4##x,y,z,v), \
philpem@5 556 I[32] = (img)(_p3##x,_n1##y,z,v), I[33] = (img)(_p2##x,_n1##y,z,v), I[34] = (img)(_p1##x,_n1##y,z,v), I[35] = (img)(x,_n1##y,z,v), \
philpem@5 557 I[36] = (img)(_n1##x,_n1##y,z,v), I[37] = (img)(_n2##x,_n1##y,z,v), I[38] = (img)(_n3##x,_n1##y,z,v), I[39] = (img)(_n4##x,_n1##y,z,v), \
philpem@5 558 I[40] = (img)(_p3##x,_n2##y,z,v), I[41] = (img)(_p2##x,_n2##y,z,v), I[42] = (img)(_p1##x,_n2##y,z,v), I[43] = (img)(x,_n2##y,z,v), \
philpem@5 559 I[44] = (img)(_n1##x,_n2##y,z,v), I[45] = (img)(_n2##x,_n2##y,z,v), I[46] = (img)(_n3##x,_n2##y,z,v), I[47] = (img)(_n4##x,_n2##y,z,v), \
philpem@5 560 I[48] = (img)(_p3##x,_n3##y,z,v), I[49] = (img)(_p2##x,_n3##y,z,v), I[50] = (img)(_p1##x,_n3##y,z,v), I[51] = (img)(x,_n3##y,z,v), \
philpem@5 561 I[52] = (img)(_n1##x,_n3##y,z,v), I[53] = (img)(_n2##x,_n3##y,z,v), I[54] = (img)(_n3##x,_n3##y,z,v), I[55] = (img)(_n4##x,_n3##y,z,v), \
philpem@5 562 I[56] = (img)(_p3##x,_n4##y,z,v), I[57] = (img)(_p2##x,_n4##y,z,v), I[58] = (img)(_p1##x,_n4##y,z,v), I[59] = (img)(x,_n4##y,z,v), \
philpem@5 563 I[60] = (img)(_n1##x,_n4##y,z,v), I[61] = (img)(_n2##x,_n4##y,z,v), I[62] = (img)(_n3##x,_n4##y,z,v), I[63] = (img)(_n4##x,_n4##y,z,v);
philpem@5 564
philpem@5 565 #define cimg_get9x9(img,x,y,z,v,I) \
philpem@5 566 I[0] = (img)(_p4##x,_p4##y,z,v), I[1] = (img)(_p3##x,_p4##y,z,v), I[2] = (img)(_p2##x,_p4##y,z,v), I[3] = (img)(_p1##x,_p4##y,z,v), \
philpem@5 567 I[4] = (img)(x,_p4##y,z,v), I[5] = (img)(_n1##x,_p4##y,z,v), I[6] = (img)(_n2##x,_p4##y,z,v), I[7] = (img)(_n3##x,_p4##y,z,v), \
philpem@5 568 I[8] = (img)(_n4##x,_p4##y,z,v), I[9] = (img)(_p4##x,_p3##y,z,v), I[10] = (img)(_p3##x,_p3##y,z,v), I[11] = (img)(_p2##x,_p3##y,z,v), \
philpem@5 569 I[12] = (img)(_p1##x,_p3##y,z,v), I[13] = (img)(x,_p3##y,z,v), I[14] = (img)(_n1##x,_p3##y,z,v), I[15] = (img)(_n2##x,_p3##y,z,v), \
philpem@5 570 I[16] = (img)(_n3##x,_p3##y,z,v), I[17] = (img)(_n4##x,_p3##y,z,v), I[18] = (img)(_p4##x,_p2##y,z,v), I[19] = (img)(_p3##x,_p2##y,z,v), \
philpem@5 571 I[20] = (img)(_p2##x,_p2##y,z,v), I[21] = (img)(_p1##x,_p2##y,z,v), I[22] = (img)(x,_p2##y,z,v), I[23] = (img)(_n1##x,_p2##y,z,v), \
philpem@5 572 I[24] = (img)(_n2##x,_p2##y,z,v), I[25] = (img)(_n3##x,_p2##y,z,v), I[26] = (img)(_n4##x,_p2##y,z,v), I[27] = (img)(_p4##x,_p1##y,z,v), \
philpem@5 573 I[28] = (img)(_p3##x,_p1##y,z,v), I[29] = (img)(_p2##x,_p1##y,z,v), I[30] = (img)(_p1##x,_p1##y,z,v), I[31] = (img)(x,_p1##y,z,v), \
philpem@5 574 I[32] = (img)(_n1##x,_p1##y,z,v), I[33] = (img)(_n2##x,_p1##y,z,v), I[34] = (img)(_n3##x,_p1##y,z,v), I[35] = (img)(_n4##x,_p1##y,z,v), \
philpem@5 575 I[36] = (img)(_p4##x,y,z,v), I[37] = (img)(_p3##x,y,z,v), I[38] = (img)(_p2##x,y,z,v), I[39] = (img)(_p1##x,y,z,v), \
philpem@5 576 I[40] = (img)(x,y,z,v), I[41] = (img)(_n1##x,y,z,v), I[42] = (img)(_n2##x,y,z,v), I[43] = (img)(_n3##x,y,z,v), \
philpem@5 577 I[44] = (img)(_n4##x,y,z,v), I[45] = (img)(_p4##x,_n1##y,z,v), I[46] = (img)(_p3##x,_n1##y,z,v), I[47] = (img)(_p2##x,_n1##y,z,v), \
philpem@5 578 I[48] = (img)(_p1##x,_n1##y,z,v), I[49] = (img)(x,_n1##y,z,v), I[50] = (img)(_n1##x,_n1##y,z,v), I[51] = (img)(_n2##x,_n1##y,z,v), \
philpem@5 579 I[52] = (img)(_n3##x,_n1##y,z,v), I[53] = (img)(_n4##x,_n1##y,z,v), I[54] = (img)(_p4##x,_n2##y,z,v), I[55] = (img)(_p3##x,_n2##y,z,v), \
philpem@5 580 I[56] = (img)(_p2##x,_n2##y,z,v), I[57] = (img)(_p1##x,_n2##y,z,v), I[58] = (img)(x,_n2##y,z,v), I[59] = (img)(_n1##x,_n2##y,z,v), \
philpem@5 581 I[60] = (img)(_n2##x,_n2##y,z,v), I[61] = (img)(_n3##x,_n2##y,z,v), I[62] = (img)(_n4##x,_n2##y,z,v), I[63] = (img)(_p4##x,_n3##y,z,v), \
philpem@5 582 I[64] = (img)(_p3##x,_n3##y,z,v), I[65] = (img)(_p2##x,_n3##y,z,v), I[66] = (img)(_p1##x,_n3##y,z,v), I[67] = (img)(x,_n3##y,z,v), \
philpem@5 583 I[68] = (img)(_n1##x,_n3##y,z,v), I[69] = (img)(_n2##x,_n3##y,z,v), I[70] = (img)(_n3##x,_n3##y,z,v), I[71] = (img)(_n4##x,_n3##y,z,v), \
philpem@5 584 I[72] = (img)(_p4##x,_n4##y,z,v), I[73] = (img)(_p3##x,_n4##y,z,v), I[74] = (img)(_p2##x,_n4##y,z,v), I[75] = (img)(_p1##x,_n4##y,z,v), \
philpem@5 585 I[76] = (img)(x,_n4##y,z,v), I[77] = (img)(_n1##x,_n4##y,z,v), I[78] = (img)(_n2##x,_n4##y,z,v), I[79] = (img)(_n3##x,_n4##y,z,v), \
philpem@5 586 I[80] = (img)(_n4##x,_n4##y,z,v)
philpem@5 587
philpem@5 588 #define cimg_get2x2x2(img,x,y,z,v,I) \
philpem@5 589 I[0] = (img)(x,y,z,v), I[1] = (img)(_n1##x,y,z,v), I[2] = (img)(x,_n1##y,z,v), I[3] = (img)(_n1##x,_n1##y,z,v), \
philpem@5 590 I[4] = (img)(x,y,_n1##z,v), I[5] = (img)(_n1##x,y,_n1##z,v), I[6] = (img)(x,_n1##y,_n1##z,v), I[7] = (img)(_n1##x,_n1##y,_n1##z,v)
philpem@5 591
philpem@5 592 #define cimg_get3x3x3(img,x,y,z,v,I) \
philpem@5 593 I[0] = (img)(_p1##x,_p1##y,_p1##z,v), I[1] = (img)(x,_p1##y,_p1##z,v), I[2] = (img)(_n1##x,_p1##y,_p1##z,v), \
philpem@5 594 I[3] = (img)(_p1##x,y,_p1##z,v), I[4] = (img)(x,y,_p1##z,v), I[5] = (img)(_n1##x,y,_p1##z,v), \
philpem@5 595 I[6] = (img)(_p1##x,_n1##y,_p1##z,v), I[7] = (img)(x,_n1##y,_p1##z,v), I[8] = (img)(_n1##x,_n1##y,_p1##z,v), \
philpem@5 596 I[9] = (img)(_p1##x,_p1##y,z,v), I[10] = (img)(x,_p1##y,z,v), I[11] = (img)(_n1##x,_p1##y,z,v), \
philpem@5 597 I[12] = (img)(_p1##x,y,z,v), I[13] = (img)(x,y,z,v), I[14] = (img)(_n1##x,y,z,v), \
philpem@5 598 I[15] = (img)(_p1##x,_n1##y,z,v), I[16] = (img)(x,_n1##y,z,v), I[17] = (img)(_n1##x,_n1##y,z,v), \
philpem@5 599 I[18] = (img)(_p1##x,_p1##y,_n1##z,v), I[19] = (img)(x,_p1##y,_n1##z,v), I[20] = (img)(_n1##x,_p1##y,_n1##z,v), \
philpem@5 600 I[21] = (img)(_p1##x,y,_n1##z,v), I[22] = (img)(x,y,_n1##z,v), I[23] = (img)(_n1##x,y,_n1##z,v), \
philpem@5 601 I[24] = (img)(_p1##x,_n1##y,_n1##z,v), I[25] = (img)(x,_n1##y,_n1##z,v), I[26] = (img)(_n1##x,_n1##y,_n1##z,v)
philpem@5 602
philpem@5 603 // Define various image loops.
philpem@5 604 //
philpem@5 605 // These macros generally avoid the use of iterators, but you are not forced to used them !
philpem@5 606 //
philpem@5 607 #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr = (img).data + (img).size(); (ptr--)>(img).data; )
philpem@5 608 #define cimg_foroff(img,off) for (unsigned int off = 0, _max##off = (unsigned int)(img).size(); off<_max##off; ++off)
philpem@5 609 #define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; ++l)
philpem@5 610 #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn
philpem@5 611
philpem@5 612 #define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i)
philpem@5 613 #define cimg_forX(img,x) cimg_for1((img).width,x)
philpem@5 614 #define cimg_forY(img,y) cimg_for1((img).height,y)
philpem@5 615 #define cimg_forZ(img,z) cimg_for1((img).depth,z)
philpem@5 616 #define cimg_forV(img,v) cimg_for1((img).dim,v)
philpem@5 617 #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x)
philpem@5 618 #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x)
philpem@5 619 #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y)
philpem@5 620 #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x)
philpem@5 621 #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y)
philpem@5 622 #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z)
philpem@5 623 #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y)
philpem@5 624 #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y)
philpem@5 625 #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z)
philpem@5 626 #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z)
philpem@5 627 #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z)
philpem@5 628
philpem@5 629 #define cimg_for_in1(bound,i0,i1,i) \
philpem@5 630 for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound)-1; i<=_max##i; ++i)
philpem@5 631 #define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img).width,x0,x1,x)
philpem@5 632 #define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img).height,y0,y1,y)
philpem@5 633 #define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img).depth,z0,z1,z)
philpem@5 634 #define cimg_for_inV(img,v0,v1,v) cimg_for_in1((img).dim,v0,v1,v)
philpem@5 635 #define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x)
philpem@5 636 #define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x)
philpem@5 637 #define cimg_for_inXV(img,x0,v0,x1,v1,x,v) cimg_for_inV(img,v0,v1,v) cimg_for_inX(img,x0,x1,x)
philpem@5 638 #define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y)
philpem@5 639 #define cimg_for_inYV(img,y0,v0,y1,v1,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inY(img,y0,y1,y)
philpem@5 640 #define cimg_for_inZV(img,z0,v0,z1,v1,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inZ(img,z0,z1,z)
philpem@5 641 #define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
philpem@5 642 #define cimg_for_inXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXY(img,x0,y0,x1,y1,x,y)
philpem@5 643 #define cimg_for_inXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXZ(img,x0,z0,x1,z1,x,z)
philpem@5 644 #define cimg_for_inYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inYZ(img,y0,z0,y1,z1,y,z)
philpem@5 645 #define cimg_for_inXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_inV(img,v0,v1,v) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 646 #define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img).width-1-(n),x)
philpem@5 647 #define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img).height-1-(n),y)
philpem@5 648 #define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img).depth-1-(n),z)
philpem@5 649 #define cimg_for_insideV(img,v,n) cimg_for_inV(img,n,(img).dim-1-(n),v)
philpem@5 650 #define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
philpem@5 651 #define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
philpem@5 652 #define cimg_for_insideXYZV(img,x,y,z,v,n) cimg_for_inXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
philpem@5 653
philpem@5 654 #define cimg_for_out1(boundi,i0,i1,i) \
philpem@5 655 for (int i = (int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1)+1:i)
philpem@5 656 #define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \
philpem@5 657 for (int j = 0; j<(int)(boundj); ++j) \
philpem@5 658 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
philpem@5 659 ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1)+1:i))
philpem@5 660 #define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \
philpem@5 661 for (int k = 0; k<(int)(boundk); ++k) \
philpem@5 662 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
philpem@5 663 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
philpem@5 664 ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1)+1:i))
philpem@5 665 #define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \
philpem@5 666 for (int l = 0; l<(int)(boundl); ++l) \
philpem@5 667 for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \
philpem@5 668 for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \
philpem@5 669 for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1)+1; i<(int)(boundi); \
philpem@5 670 ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1)+1:i))
philpem@5 671 #define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img).width,x0,x1,x)
philpem@5 672 #define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img).height,y0,y1,y)
philpem@5 673 #define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img).depth,z0,z1,z)
philpem@5 674 #define cimg_for_outV(img,v0,v1,v) cimg_for_out1((img).dim,v0,v1,v)
philpem@5 675 #define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img).width,(img).height,x0,y0,x1,y1,x,y)
philpem@5 676 #define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img).width,(img).depth,x0,z0,x1,z1,x,z)
philpem@5 677 #define cimg_for_outXV(img,x0,v0,x1,v1,x,v) cimg_for_out2((img).width,(img).dim,x0,v0,x1,v1,x,v)
philpem@5 678 #define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img).height,(img).depth,y0,z0,y1,z1,y,z)
philpem@5 679 #define cimg_for_outYV(img,y0,v0,y1,v1,y,v) cimg_for_out2((img).height,(img).dim,y0,v0,y1,v1,y,v)
philpem@5 680 #define cimg_for_outZV(img,z0,v0,z1,v1,z,v) cimg_for_out2((img).depth,(img).dim,z0,v0,z1,v1,z,v)
philpem@5 681 #define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_out3((img).width,(img).height,(img).depth,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 682 #define cimg_for_outXYV(img,x0,y0,v0,x1,y1,v1,x,y,v) cimg_for_out3((img).width,(img).height,(img).dim,x0,y0,v0,x1,y1,v1,x,y,v)
philpem@5 683 #define cimg_for_outXZV(img,x0,z0,v0,x1,z1,v1,x,z,v) cimg_for_out3((img).width,(img).depth,(img).dim,x0,z0,v0,x1,z1,v1,x,z,v)
philpem@5 684 #define cimg_for_outYZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_out3((img).height,(img).depth,(img).dim,y0,z0,v0,y1,z1,v1,y,z,v)
philpem@5 685 #define cimg_for_outXYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) \
philpem@5 686 cimg_for_out4((img).width,(img).height,(img).depth,(img).dim,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v)
philpem@5 687 #define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img).width-1-(n),x)
philpem@5 688 #define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img).height-1-(n),y)
philpem@5 689 #define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img).depth-1-(n),z)
philpem@5 690 #define cimg_for_borderV(img,v,n) cimg_for_outV(img,n,(img).dim-1-(n),v)
philpem@5 691 #define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img).width-1-(n),(img).height-1-(n),x,y)
philpem@5 692 #define cimg_for_borderXYZ(img,x,y,z,n) cimg_for_outXYZ(img,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),x,y,z)
philpem@5 693 #define cimg_for_borderXYZV(img,x,y,z,v,n) \
philpem@5 694 cimg_for_outXYZV(img,n,n,n,n,(img).width-1-(n),(img).height-1-(n),(img).depth-1-(n),(img).dim-1-(n),x,y,z,v)
philpem@5 695
philpem@5 696 #define cimg_for_spiralXY(img,x,y) \
philpem@5 697 for (int x = 0, y = 0, _n1##x = 1, _n1##y = (int)((img).width*(img).height); _n1##y; \
philpem@5 698 --_n1##y, _n1##x += (_n1##x>>2)-((!(_n1##x&3)?--y:((_n1##x&3)==1?(img).width-1-++x:((_n1##x&3)==2?(img).height-1-++y:--x))))?0:1)
philpem@5 699
philpem@5 700 #define cimg_for_lineXY(x,y,x0,y0,x1,y1) \
philpem@5 701 for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \
philpem@5 702 _dx=(x1)>(x0)?(int)(x1)-(int)(x0):(_sx=-1,(int)(x0)-(int)(x1)), \
philpem@5 703 _dy=(y1)>(y0)?(int)(y1)-(int)(y0):(_sy=-1,(int)(y0)-(int)(y1)), \
philpem@5 704 _counter = _dx, \
philpem@5 705 _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \
philpem@5 706 _counter>=0; \
philpem@5 707 --_counter, x+=_steep? \
philpem@5 708 (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \
philpem@5 709 (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx))
philpem@5 710
philpem@5 711 #define cimg_for2(bound,i) \
philpem@5 712 for (int i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1; \
philpem@5 713 _n1##i<(int)(bound) || i==--_n1##i; \
philpem@5 714 ++i, ++_n1##i)
philpem@5 715 #define cimg_for2X(img,x) cimg_for2((img).width,x)
philpem@5 716 #define cimg_for2Y(img,y) cimg_for2((img).height,y)
philpem@5 717 #define cimg_for2Z(img,z) cimg_for2((img).depth,z)
philpem@5 718 #define cimg_for2V(img,v) cimg_for2((img).dim,v)
philpem@5 719 #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x)
philpem@5 720 #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x)
philpem@5 721 #define cimg_for2XV(img,x,v) cimg_for2V(img,v) cimg_for2X(img,x)
philpem@5 722 #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y)
philpem@5 723 #define cimg_for2YV(img,y,v) cimg_for2V(img,v) cimg_for2Y(img,y)
philpem@5 724 #define cimg_for2ZV(img,z,v) cimg_for2V(img,v) cimg_for2Z(img,z)
philpem@5 725 #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y)
philpem@5 726 #define cimg_for2XZV(img,x,z,v) cimg_for2V(img,v) cimg_for2XZ(img,x,z)
philpem@5 727 #define cimg_for2YZV(img,y,z,v) cimg_for2V(img,v) cimg_for2YZ(img,y,z)
philpem@5 728 #define cimg_for2XYZV(img,x,y,z,v) cimg_for2V(img,v) cimg_for2XYZ(img,x,y,z)
philpem@5 729
philpem@5 730 #define cimg_for_in2(bound,i0,i1,i) \
philpem@5 731 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 732 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
philpem@5 733 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
philpem@5 734 ++i, ++_n1##i)
philpem@5 735 #define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img).width,x0,x1,x)
philpem@5 736 #define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img).height,y0,y1,y)
philpem@5 737 #define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img).depth,z0,z1,z)
philpem@5 738 #define cimg_for_in2V(img,v0,v1,v) cimg_for_in2((img).dim,v0,v1,v)
philpem@5 739 #define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x)
philpem@5 740 #define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x)
philpem@5 741 #define cimg_for_in2XV(img,x0,v0,x1,v1,x,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2X(img,x0,x1,x)
philpem@5 742 #define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y)
philpem@5 743 #define cimg_for_in2YV(img,y0,v0,y1,v1,y,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Y(img,y0,y1,y)
philpem@5 744 #define cimg_for_in2ZV(img,z0,v0,z1,v1,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2Z(img,z0,z1,z)
philpem@5 745 #define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y)
philpem@5 746 #define cimg_for_in2XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z)
philpem@5 747 #define cimg_for_in2YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z)
philpem@5 748 #define cimg_for_in2XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in2V(img,v0,v1,v) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 749
philpem@5 750 #define cimg_for3(bound,i) \
philpem@5 751 for (int i = 0, _p1##i = 0, \
philpem@5 752 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
philpem@5 753 _n1##i<(int)(bound) || i==--_n1##i; \
philpem@5 754 _p1##i = i++, ++_n1##i)
philpem@5 755 #define cimg_for3X(img,x) cimg_for3((img).width,x)
philpem@5 756 #define cimg_for3Y(img,y) cimg_for3((img).height,y)
philpem@5 757 #define cimg_for3Z(img,z) cimg_for3((img).depth,z)
philpem@5 758 #define cimg_for3V(img,v) cimg_for3((img).dim,v)
philpem@5 759 #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x)
philpem@5 760 #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x)
philpem@5 761 #define cimg_for3XV(img,x,v) cimg_for3V(img,v) cimg_for3X(img,x)
philpem@5 762 #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y)
philpem@5 763 #define cimg_for3YV(img,y,v) cimg_for3V(img,v) cimg_for3Y(img,y)
philpem@5 764 #define cimg_for3ZV(img,z,v) cimg_for3V(img,v) cimg_for3Z(img,z)
philpem@5 765 #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y)
philpem@5 766 #define cimg_for3XZV(img,x,z,v) cimg_for3V(img,v) cimg_for3XZ(img,x,z)
philpem@5 767 #define cimg_for3YZV(img,y,z,v) cimg_for3V(img,v) cimg_for3YZ(img,y,z)
philpem@5 768 #define cimg_for3XYZV(img,x,y,z,v) cimg_for3V(img,v) cimg_for3XYZ(img,x,y,z)
philpem@5 769
philpem@5 770 #define cimg_for_in3(bound,i0,i1,i) \
philpem@5 771 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 772 _p1##i = i-1<0?0:i-1, \
philpem@5 773 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1; \
philpem@5 774 i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \
philpem@5 775 _p1##i = i++, ++_n1##i)
philpem@5 776 #define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img).width,x0,x1,x)
philpem@5 777 #define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img).height,y0,y1,y)
philpem@5 778 #define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img).depth,z0,z1,z)
philpem@5 779 #define cimg_for_in3V(img,v0,v1,v) cimg_for_in3((img).dim,v0,v1,v)
philpem@5 780 #define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x)
philpem@5 781 #define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x)
philpem@5 782 #define cimg_for_in3XV(img,x0,v0,x1,v1,x,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3X(img,x0,x1,x)
philpem@5 783 #define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y)
philpem@5 784 #define cimg_for_in3YV(img,y0,v0,y1,v1,y,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Y(img,y0,y1,y)
philpem@5 785 #define cimg_for_in3ZV(img,z0,v0,z1,v1,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3Z(img,z0,z1,z)
philpem@5 786 #define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y)
philpem@5 787 #define cimg_for_in3XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z)
philpem@5 788 #define cimg_for_in3YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z)
philpem@5 789 #define cimg_for_in3XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in3V(img,v0,v1,v) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 790
philpem@5 791 #define cimg_for4(bound,i) \
philpem@5 792 for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound)-1:1, \
philpem@5 793 _n2##i = 2>=(bound)?(int)(bound)-1:2; \
philpem@5 794 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
philpem@5 795 _p1##i = i++, ++_n1##i, ++_n2##i)
philpem@5 796 #define cimg_for4X(img,x) cimg_for4((img).width,x)
philpem@5 797 #define cimg_for4Y(img,y) cimg_for4((img).height,y)
philpem@5 798 #define cimg_for4Z(img,z) cimg_for4((img).depth,z)
philpem@5 799 #define cimg_for4V(img,v) cimg_for4((img).dim,v)
philpem@5 800 #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x)
philpem@5 801 #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x)
philpem@5 802 #define cimg_for4XV(img,x,v) cimg_for4V(img,v) cimg_for4X(img,x)
philpem@5 803 #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y)
philpem@5 804 #define cimg_for4YV(img,y,v) cimg_for4V(img,v) cimg_for4Y(img,y)
philpem@5 805 #define cimg_for4ZV(img,z,v) cimg_for4V(img,v) cimg_for4Z(img,z)
philpem@5 806 #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y)
philpem@5 807 #define cimg_for4XZV(img,x,z,v) cimg_for4V(img,v) cimg_for4XZ(img,x,z)
philpem@5 808 #define cimg_for4YZV(img,y,z,v) cimg_for4V(img,v) cimg_for4YZ(img,y,z)
philpem@5 809 #define cimg_for4XYZV(img,x,y,z,v) cimg_for4V(img,v) cimg_for4XYZ(img,x,y,z)
philpem@5 810
philpem@5 811 #define cimg_for_in4(bound,i0,i1,i) \
philpem@5 812 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 813 _p1##i = i-1<0?0:i-1, \
philpem@5 814 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 815 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
philpem@5 816 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
philpem@5 817 _p1##i = i++, ++_n1##i, ++_n2##i)
philpem@5 818 #define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img).width,x0,x1,x)
philpem@5 819 #define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img).height,y0,y1,y)
philpem@5 820 #define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img).depth,z0,z1,z)
philpem@5 821 #define cimg_for_in4V(img,v0,v1,v) cimg_for_in4((img).dim,v0,v1,v)
philpem@5 822 #define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x)
philpem@5 823 #define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x)
philpem@5 824 #define cimg_for_in4XV(img,x0,v0,x1,v1,x,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4X(img,x0,x1,x)
philpem@5 825 #define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y)
philpem@5 826 #define cimg_for_in4YV(img,y0,v0,y1,v1,y,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Y(img,y0,y1,y)
philpem@5 827 #define cimg_for_in4ZV(img,z0,v0,z1,v1,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4Z(img,z0,z1,z)
philpem@5 828 #define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y)
philpem@5 829 #define cimg_for_in4XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z)
philpem@5 830 #define cimg_for_in4YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z)
philpem@5 831 #define cimg_for_in4XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in4V(img,v0,v1,v) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 832
philpem@5 833 #define cimg_for5(bound,i) \
philpem@5 834 for (int i = 0, _p2##i = 0, _p1##i = 0, \
philpem@5 835 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
philpem@5 836 _n2##i = 2>=(bound)?(int)(bound)-1:2; \
philpem@5 837 _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \
philpem@5 838 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
philpem@5 839 #define cimg_for5X(img,x) cimg_for5((img).width,x)
philpem@5 840 #define cimg_for5Y(img,y) cimg_for5((img).height,y)
philpem@5 841 #define cimg_for5Z(img,z) cimg_for5((img).depth,z)
philpem@5 842 #define cimg_for5V(img,v) cimg_for5((img).dim,v)
philpem@5 843 #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x)
philpem@5 844 #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x)
philpem@5 845 #define cimg_for5XV(img,x,v) cimg_for5V(img,v) cimg_for5X(img,x)
philpem@5 846 #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y)
philpem@5 847 #define cimg_for5YV(img,y,v) cimg_for5V(img,v) cimg_for5Y(img,y)
philpem@5 848 #define cimg_for5ZV(img,z,v) cimg_for5V(img,v) cimg_for5Z(img,z)
philpem@5 849 #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y)
philpem@5 850 #define cimg_for5XZV(img,x,z,v) cimg_for5V(img,v) cimg_for5XZ(img,x,z)
philpem@5 851 #define cimg_for5YZV(img,y,z,v) cimg_for5V(img,v) cimg_for5YZ(img,y,z)
philpem@5 852 #define cimg_for5XYZV(img,x,y,z,v) cimg_for5V(img,v) cimg_for5XYZ(img,x,y,z)
philpem@5 853
philpem@5 854 #define cimg_for_in5(bound,i0,i1,i) \
philpem@5 855 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 856 _p2##i = i-2<0?0:i-2, \
philpem@5 857 _p1##i = i-1<0?0:i-1, \
philpem@5 858 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 859 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2; \
philpem@5 860 i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \
philpem@5 861 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i)
philpem@5 862 #define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img).width,x0,x1,x)
philpem@5 863 #define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img).height,y0,y1,y)
philpem@5 864 #define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img).depth,z0,z1,z)
philpem@5 865 #define cimg_for_in5V(img,v0,v1,v) cimg_for_in5((img).dim,v0,v1,v)
philpem@5 866 #define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x)
philpem@5 867 #define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x)
philpem@5 868 #define cimg_for_in5XV(img,x0,v0,x1,v1,x,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5X(img,x0,x1,x)
philpem@5 869 #define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y)
philpem@5 870 #define cimg_for_in5YV(img,y0,v0,y1,v1,y,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Y(img,y0,y1,y)
philpem@5 871 #define cimg_for_in5ZV(img,z0,v0,z1,v1,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5Z(img,z0,z1,z)
philpem@5 872 #define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y)
philpem@5 873 #define cimg_for_in5XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z)
philpem@5 874 #define cimg_for_in5YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z)
philpem@5 875 #define cimg_for_in5XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in5V(img,v0,v1,v) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 876
philpem@5 877 #define cimg_for6(bound,i) \
philpem@5 878 for (int i = 0, _p2##i = 0, _p1##i = 0, \
philpem@5 879 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
philpem@5 880 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
philpem@5 881 _n3##i = 3>=(bound)?(int)(bound)-1:3; \
philpem@5 882 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
philpem@5 883 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
philpem@5 884 #define cimg_for6X(img,x) cimg_for6((img).width,x)
philpem@5 885 #define cimg_for6Y(img,y) cimg_for6((img).height,y)
philpem@5 886 #define cimg_for6Z(img,z) cimg_for6((img).depth,z)
philpem@5 887 #define cimg_for6V(img,v) cimg_for6((img).dim,v)
philpem@5 888 #define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x)
philpem@5 889 #define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x)
philpem@5 890 #define cimg_for6XV(img,x,v) cimg_for6V(img,v) cimg_for6X(img,x)
philpem@5 891 #define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y)
philpem@5 892 #define cimg_for6YV(img,y,v) cimg_for6V(img,v) cimg_for6Y(img,y)
philpem@5 893 #define cimg_for6ZV(img,z,v) cimg_for6V(img,v) cimg_for6Z(img,z)
philpem@5 894 #define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y)
philpem@5 895 #define cimg_for6XZV(img,x,z,v) cimg_for6V(img,v) cimg_for6XZ(img,x,z)
philpem@5 896 #define cimg_for6YZV(img,y,z,v) cimg_for6V(img,v) cimg_for6YZ(img,y,z)
philpem@5 897 #define cimg_for6XYZV(img,x,y,z,v) cimg_for6V(img,v) cimg_for6XYZ(img,x,y,z)
philpem@5 898
philpem@5 899 #define cimg_for_in6(bound,i0,i1,i) \
philpem@5 900 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 901 _p2##i = i-2<0?0:i-2, \
philpem@5 902 _p1##i = i-1<0?0:i-1, \
philpem@5 903 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 904 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
philpem@5 905 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
philpem@5 906 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
philpem@5 907 _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
philpem@5 908 #define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img).width,x0,x1,x)
philpem@5 909 #define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img).height,y0,y1,y)
philpem@5 910 #define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img).depth,z0,z1,z)
philpem@5 911 #define cimg_for_in6V(img,v0,v1,v) cimg_for_in6((img).dim,v0,v1,v)
philpem@5 912 #define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x)
philpem@5 913 #define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x)
philpem@5 914 #define cimg_for_in6XV(img,x0,v0,x1,v1,x,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6X(img,x0,x1,x)
philpem@5 915 #define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y)
philpem@5 916 #define cimg_for_in6YV(img,y0,v0,y1,v1,y,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Y(img,y0,y1,y)
philpem@5 917 #define cimg_for_in6ZV(img,z0,v0,z1,v1,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6Z(img,z0,z1,z)
philpem@5 918 #define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y)
philpem@5 919 #define cimg_for_in6XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z)
philpem@5 920 #define cimg_for_in6YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z)
philpem@5 921 #define cimg_for_in6XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in6V(img,v0,v1,v) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 922
philpem@5 923 #define cimg_for7(bound,i) \
philpem@5 924 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
philpem@5 925 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
philpem@5 926 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
philpem@5 927 _n3##i = 3>=(bound)?(int)(bound)-1:3; \
philpem@5 928 _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \
philpem@5 929 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
philpem@5 930 #define cimg_for7X(img,x) cimg_for7((img).width,x)
philpem@5 931 #define cimg_for7Y(img,y) cimg_for7((img).height,y)
philpem@5 932 #define cimg_for7Z(img,z) cimg_for7((img).depth,z)
philpem@5 933 #define cimg_for7V(img,v) cimg_for7((img).dim,v)
philpem@5 934 #define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x)
philpem@5 935 #define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x)
philpem@5 936 #define cimg_for7XV(img,x,v) cimg_for7V(img,v) cimg_for7X(img,x)
philpem@5 937 #define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y)
philpem@5 938 #define cimg_for7YV(img,y,v) cimg_for7V(img,v) cimg_for7Y(img,y)
philpem@5 939 #define cimg_for7ZV(img,z,v) cimg_for7V(img,v) cimg_for7Z(img,z)
philpem@5 940 #define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y)
philpem@5 941 #define cimg_for7XZV(img,x,z,v) cimg_for7V(img,v) cimg_for7XZ(img,x,z)
philpem@5 942 #define cimg_for7YZV(img,y,z,v) cimg_for7V(img,v) cimg_for7YZ(img,y,z)
philpem@5 943 #define cimg_for7XYZV(img,x,y,z,v) cimg_for7V(img,v) cimg_for7XYZ(img,x,y,z)
philpem@5 944
philpem@5 945 #define cimg_for_in7(bound,i0,i1,i) \
philpem@5 946 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 947 _p3##i = i-3<0?0:i-3, \
philpem@5 948 _p2##i = i-2<0?0:i-2, \
philpem@5 949 _p1##i = i-1<0?0:i-1, \
philpem@5 950 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 951 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
philpem@5 952 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3; \
philpem@5 953 i<=(int)(i1) && (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \
philpem@5 954 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i)
philpem@5 955 #define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img).width,x0,x1,x)
philpem@5 956 #define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img).height,y0,y1,y)
philpem@5 957 #define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img).depth,z0,z1,z)
philpem@5 958 #define cimg_for_in7V(img,v0,v1,v) cimg_for_in7((img).dim,v0,v1,v)
philpem@5 959 #define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x)
philpem@5 960 #define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x)
philpem@5 961 #define cimg_for_in7XV(img,x0,v0,x1,v1,x,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7X(img,x0,x1,x)
philpem@5 962 #define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y)
philpem@5 963 #define cimg_for_in7YV(img,y0,v0,y1,v1,y,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Y(img,y0,y1,y)
philpem@5 964 #define cimg_for_in7ZV(img,z0,v0,z1,v1,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7Z(img,z0,z1,z)
philpem@5 965 #define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y)
philpem@5 966 #define cimg_for_in7XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z)
philpem@5 967 #define cimg_for_in7YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z)
philpem@5 968 #define cimg_for_in7XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in7V(img,v0,v1,v) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 969
philpem@5 970 #define cimg_for8(bound,i) \
philpem@5 971 for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
philpem@5 972 _n1##i = 1>=(bound)?(int)(bound)-1:1, \
philpem@5 973 _n2##i = 2>=(bound)?(int)(bound)-1:2, \
philpem@5 974 _n3##i = 3>=(bound)?(int)(bound)-1:3, \
philpem@5 975 _n4##i = 4>=(bound)?(int)(bound)-1:4; \
philpem@5 976 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
philpem@5 977 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
philpem@5 978 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
philpem@5 979 #define cimg_for8X(img,x) cimg_for8((img).width,x)
philpem@5 980 #define cimg_for8Y(img,y) cimg_for8((img).height,y)
philpem@5 981 #define cimg_for8Z(img,z) cimg_for8((img).depth,z)
philpem@5 982 #define cimg_for8V(img,v) cimg_for8((img).dim,v)
philpem@5 983 #define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x)
philpem@5 984 #define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x)
philpem@5 985 #define cimg_for8XV(img,x,v) cimg_for8V(img,v) cimg_for8X(img,x)
philpem@5 986 #define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y)
philpem@5 987 #define cimg_for8YV(img,y,v) cimg_for8V(img,v) cimg_for8Y(img,y)
philpem@5 988 #define cimg_for8ZV(img,z,v) cimg_for8V(img,v) cimg_for8Z(img,z)
philpem@5 989 #define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y)
philpem@5 990 #define cimg_for8XZV(img,x,z,v) cimg_for8V(img,v) cimg_for8XZ(img,x,z)
philpem@5 991 #define cimg_for8YZV(img,y,z,v) cimg_for8V(img,v) cimg_for8YZ(img,y,z)
philpem@5 992 #define cimg_for8XYZV(img,x,y,z,v) cimg_for8V(img,v) cimg_for8XYZ(img,x,y,z)
philpem@5 993
philpem@5 994 #define cimg_for_in8(bound,i0,i1,i) \
philpem@5 995 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 996 _p3##i = i-3<0?0:i-3, \
philpem@5 997 _p2##i = i-2<0?0:i-2, \
philpem@5 998 _p1##i = i-1<0?0:i-1, \
philpem@5 999 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 1000 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
philpem@5 1001 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
philpem@5 1002 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
philpem@5 1003 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
philpem@5 1004 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
philpem@5 1005 _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
philpem@5 1006 #define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img).width,x0,x1,x)
philpem@5 1007 #define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img).height,y0,y1,y)
philpem@5 1008 #define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img).depth,z0,z1,z)
philpem@5 1009 #define cimg_for_in8V(img,v0,v1,v) cimg_for_in8((img).dim,v0,v1,v)
philpem@5 1010 #define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x)
philpem@5 1011 #define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x)
philpem@5 1012 #define cimg_for_in8XV(img,x0,v0,x1,v1,x,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8X(img,x0,x1,x)
philpem@5 1013 #define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y)
philpem@5 1014 #define cimg_for_in8YV(img,y0,v0,y1,v1,y,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Y(img,y0,y1,y)
philpem@5 1015 #define cimg_for_in8ZV(img,z0,v0,z1,v1,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8Z(img,z0,z1,z)
philpem@5 1016 #define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y)
philpem@5 1017 #define cimg_for_in8XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z)
philpem@5 1018 #define cimg_for_in8YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z)
philpem@5 1019 #define cimg_for_in8XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in8V(img,v0,v1,v) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 1020
philpem@5 1021 #define cimg_for9(bound,i) \
philpem@5 1022 for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \
philpem@5 1023 _n1##i = 1>=(int)(bound)?(int)(bound)-1:1, \
philpem@5 1024 _n2##i = 2>=(int)(bound)?(int)(bound)-1:2, \
philpem@5 1025 _n3##i = 3>=(int)(bound)?(int)(bound)-1:3, \
philpem@5 1026 _n4##i = 4>=(int)(bound)?(int)(bound)-1:4; \
philpem@5 1027 _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
philpem@5 1028 i==(_n4##i = _n3##i = _n2##i = --_n1##i); \
philpem@5 1029 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
philpem@5 1030 #define cimg_for9X(img,x) cimg_for9((img).width,x)
philpem@5 1031 #define cimg_for9Y(img,y) cimg_for9((img).height,y)
philpem@5 1032 #define cimg_for9Z(img,z) cimg_for9((img).depth,z)
philpem@5 1033 #define cimg_for9V(img,v) cimg_for9((img).dim,v)
philpem@5 1034 #define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x)
philpem@5 1035 #define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x)
philpem@5 1036 #define cimg_for9XV(img,x,v) cimg_for9V(img,v) cimg_for9X(img,x)
philpem@5 1037 #define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y)
philpem@5 1038 #define cimg_for9YV(img,y,v) cimg_for9V(img,v) cimg_for9Y(img,y)
philpem@5 1039 #define cimg_for9ZV(img,z,v) cimg_for9V(img,v) cimg_for9Z(img,z)
philpem@5 1040 #define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y)
philpem@5 1041 #define cimg_for9XZV(img,x,z,v) cimg_for9V(img,v) cimg_for9XZ(img,x,z)
philpem@5 1042 #define cimg_for9YZV(img,y,z,v) cimg_for9V(img,v) cimg_for9YZ(img,y,z)
philpem@5 1043 #define cimg_for9XYZV(img,x,y,z,v) cimg_for9V(img,v) cimg_for9XYZ(img,x,y,z)
philpem@5 1044
philpem@5 1045 #define cimg_for_in9(bound,i0,i1,i) \
philpem@5 1046 for (int i = (int)(i0)<0?0:(int)(i0), \
philpem@5 1047 _p4##i = i-4<0?0:i-4, \
philpem@5 1048 _p3##i = i-3<0?0:i-3, \
philpem@5 1049 _p2##i = i-2<0?0:i-2, \
philpem@5 1050 _p1##i = i-1<0?0:i-1, \
philpem@5 1051 _n1##i = i+1>=(int)(bound)?(int)(bound)-1:i+1, \
philpem@5 1052 _n2##i = i+2>=(int)(bound)?(int)(bound)-1:i+2, \
philpem@5 1053 _n3##i = i+3>=(int)(bound)?(int)(bound)-1:i+3, \
philpem@5 1054 _n4##i = i+4>=(int)(bound)?(int)(bound)-1:i+4; \
philpem@5 1055 i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \
philpem@5 1056 i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \
philpem@5 1057 _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i)
philpem@5 1058 #define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img).width,x0,x1,x)
philpem@5 1059 #define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img).height,y0,y1,y)
philpem@5 1060 #define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img).depth,z0,z1,z)
philpem@5 1061 #define cimg_for_in9V(img,v0,v1,v) cimg_for_in9((img).dim,v0,v1,v)
philpem@5 1062 #define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x)
philpem@5 1063 #define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x)
philpem@5 1064 #define cimg_for_in9XV(img,x0,v0,x1,v1,x,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9X(img,x0,x1,x)
philpem@5 1065 #define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y)
philpem@5 1066 #define cimg_for_in9YV(img,y0,v0,y1,v1,y,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Y(img,y0,y1,y)
philpem@5 1067 #define cimg_for_in9ZV(img,z0,v0,z1,v1,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9Z(img,z0,z1,z)
philpem@5 1068 #define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y)
philpem@5 1069 #define cimg_for_in9XZV(img,x0,z0,v0,x1,y1,v1,x,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z)
philpem@5 1070 #define cimg_for_in9YZV(img,y0,z0,v0,y1,z1,v1,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z)
philpem@5 1071 #define cimg_for_in9XYZV(img,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) cimg_for_in9V(img,v0,v1,v) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z)
philpem@5 1072
philpem@5 1073 #define cimg_for2x2(img,x,y,z,v,I) \
philpem@5 1074 cimg_for2((img).height,y) for (int x = 0, \
philpem@5 1075 _n1##x = (int)( \
philpem@5 1076 (I[0] = (img)(0,y,z,v)), \
philpem@5 1077 (I[2] = (img)(0,_n1##y,z,v)), \
philpem@5 1078 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 1079 (_n1##x<(int)((img).width) && ( \
philpem@5 1080 (I[1] = (img)(_n1##x,y,z,v)), \
philpem@5 1081 (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 1082 x==--_n1##x; \
philpem@5 1083 I[0] = I[1], \
philpem@5 1084 I[2] = I[3], \
philpem@5 1085 ++x, ++_n1##x)
philpem@5 1086
philpem@5 1087 #define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1088 cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1089 _n1##x = (int)( \
philpem@5 1090 (I[0] = (img)(x,y,z,v)), \
philpem@5 1091 (I[2] = (img)(x,_n1##y,z,v)), \
philpem@5 1092 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
philpem@5 1093 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
philpem@5 1094 (I[1] = (img)(_n1##x,y,z,v)), \
philpem@5 1095 (I[3] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 1096 x==--_n1##x); \
philpem@5 1097 I[0] = I[1], \
philpem@5 1098 I[2] = I[3], \
philpem@5 1099 ++x, ++_n1##x)
philpem@5 1100
philpem@5 1101 #define cimg_for3x3(img,x,y,z,v,I) \
philpem@5 1102 cimg_for3((img).height,y) for (int x = 0, \
philpem@5 1103 _p1##x = 0, \
philpem@5 1104 _n1##x = (int)( \
philpem@5 1105 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
philpem@5 1106 (I[3] = I[4] = (img)(0,y,z,v)), \
philpem@5 1107 (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
philpem@5 1108 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 1109 (_n1##x<(int)((img).width) && ( \
philpem@5 1110 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1111 (I[5] = (img)(_n1##x,y,z,v)), \
philpem@5 1112 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 1113 x==--_n1##x; \
philpem@5 1114 I[0] = I[1], I[1] = I[2], \
philpem@5 1115 I[3] = I[4], I[4] = I[5], \
philpem@5 1116 I[6] = I[7], I[7] = I[8], \
philpem@5 1117 _p1##x = x++, ++_n1##x)
philpem@5 1118
philpem@5 1119 #define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1120 cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1121 _p1##x = x-1<0?0:x-1, \
philpem@5 1122 _n1##x = (int)( \
philpem@5 1123 (I[0] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1124 (I[3] = (img)(_p1##x,y,z,v)), \
philpem@5 1125 (I[6] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1126 (I[1] = (img)(x,_p1##y,z,v)), \
philpem@5 1127 (I[4] = (img)(x,y,z,v)), \
philpem@5 1128 (I[7] = (img)(x,_n1##y,z,v)), \
philpem@5 1129 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
philpem@5 1130 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
philpem@5 1131 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1132 (I[5] = (img)(_n1##x,y,z,v)), \
philpem@5 1133 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 1134 x==--_n1##x); \
philpem@5 1135 I[0] = I[1], I[1] = I[2], \
philpem@5 1136 I[3] = I[4], I[4] = I[5], \
philpem@5 1137 I[6] = I[7], I[7] = I[8], \
philpem@5 1138 _p1##x = x++, ++_n1##x)
philpem@5 1139
philpem@5 1140 #define cimg_for4x4(img,x,y,z,v,I) \
philpem@5 1141 cimg_for4((img).height,y) for (int x = 0, \
philpem@5 1142 _p1##x = 0, \
philpem@5 1143 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
philpem@5 1144 _n2##x = (int)( \
philpem@5 1145 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
philpem@5 1146 (I[4] = I[5] = (img)(0,y,z,v)), \
philpem@5 1147 (I[8] = I[9] = (img)(0,_n1##y,z,v)), \
philpem@5 1148 (I[12] = I[13] = (img)(0,_n2##y,z,v)), \
philpem@5 1149 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1150 (I[6] = (img)(_n1##x,y,z,v)), \
philpem@5 1151 (I[10] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1152 (I[14] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1153 2>=(img).width?(int)((img).width)-1:2); \
philpem@5 1154 (_n2##x<(int)((img).width) && ( \
philpem@5 1155 (I[3] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1156 (I[7] = (img)(_n2##x,y,z,v)), \
philpem@5 1157 (I[11] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1158 (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
philpem@5 1159 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
philpem@5 1160 I[0] = I[1], I[1] = I[2], I[2] = I[3], \
philpem@5 1161 I[4] = I[5], I[5] = I[6], I[6] = I[7], \
philpem@5 1162 I[8] = I[9], I[9] = I[10], I[10] = I[11], \
philpem@5 1163 I[12] = I[13], I[13] = I[14], I[14] = I[15], \
philpem@5 1164 _p1##x = x++, ++_n1##x, ++_n2##x)
philpem@5 1165
philpem@5 1166 #define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1167 cimg_for_in4((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1168 _p1##x = x-1<0?0:x-1, \
philpem@5 1169 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
philpem@5 1170 _n2##x = (int)( \
philpem@5 1171 (I[0] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1172 (I[4] = (img)(_p1##x,y,z,v)), \
philpem@5 1173 (I[8] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1174 (I[12] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1175 (I[1] = (img)(x,_p1##y,z,v)), \
philpem@5 1176 (I[5] = (img)(x,y,z,v)), \
philpem@5 1177 (I[9] = (img)(x,_n1##y,z,v)), \
philpem@5 1178 (I[13] = (img)(x,_n2##y,z,v)), \
philpem@5 1179 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1180 (I[6] = (img)(_n1##x,y,z,v)), \
philpem@5 1181 (I[10] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1182 (I[14] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1183 x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
philpem@5 1184 x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
philpem@5 1185 (I[3] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1186 (I[7] = (img)(_n2##x,y,z,v)), \
philpem@5 1187 (I[11] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1188 (I[15] = (img)(_n2##x,_n2##y,z,v)),1)) || \
philpem@5 1189 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
philpem@5 1190 I[0] = I[1], I[1] = I[2], I[2] = I[3], \
philpem@5 1191 I[4] = I[5], I[5] = I[6], I[6] = I[7], \
philpem@5 1192 I[8] = I[9], I[9] = I[10], I[10] = I[11], \
philpem@5 1193 I[12] = I[13], I[13] = I[14], I[14] = I[15], \
philpem@5 1194 _p1##x = x++, ++_n1##x, ++_n2##x)
philpem@5 1195
philpem@5 1196 #define cimg_for5x5(img,x,y,z,v,I) \
philpem@5 1197 cimg_for5((img).height,y) for (int x = 0, \
philpem@5 1198 _p2##x = 0, _p1##x = 0, \
philpem@5 1199 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
philpem@5 1200 _n2##x = (int)( \
philpem@5 1201 (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
philpem@5 1202 (I[5] = I[6] = I[7] = (img)(0,_p1##y,z,v)), \
philpem@5 1203 (I[10] = I[11] = I[12] = (img)(0,y,z,v)), \
philpem@5 1204 (I[15] = I[16] = I[17] = (img)(0,_n1##y,z,v)), \
philpem@5 1205 (I[20] = I[21] = I[22] = (img)(0,_n2##y,z,v)), \
philpem@5 1206 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1207 (I[8] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1208 (I[13] = (img)(_n1##x,y,z,v)), \
philpem@5 1209 (I[18] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1210 (I[23] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1211 2>=(img).width?(int)((img).width)-1:2); \
philpem@5 1212 (_n2##x<(int)((img).width) && ( \
philpem@5 1213 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1214 (I[9] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1215 (I[14] = (img)(_n2##x,y,z,v)), \
philpem@5 1216 (I[19] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1217 (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
philpem@5 1218 _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \
philpem@5 1219 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
philpem@5 1220 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
philpem@5 1221 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
philpem@5 1222 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
philpem@5 1223 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
philpem@5 1224 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
philpem@5 1225
philpem@5 1226 #define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1227 cimg_for_in5((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1228 _p2##x = x-2<0?0:x-2, \
philpem@5 1229 _p1##x = x-1<0?0:x-1, \
philpem@5 1230 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
philpem@5 1231 _n2##x = (int)( \
philpem@5 1232 (I[0] = (img)(_p2##x,_p2##y,z,v)), \
philpem@5 1233 (I[5] = (img)(_p2##x,_p1##y,z,v)), \
philpem@5 1234 (I[10] = (img)(_p2##x,y,z,v)), \
philpem@5 1235 (I[15] = (img)(_p2##x,_n1##y,z,v)), \
philpem@5 1236 (I[20] = (img)(_p2##x,_n2##y,z,v)), \
philpem@5 1237 (I[1] = (img)(_p1##x,_p2##y,z,v)), \
philpem@5 1238 (I[6] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1239 (I[11] = (img)(_p1##x,y,z,v)), \
philpem@5 1240 (I[16] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1241 (I[21] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1242 (I[2] = (img)(x,_p2##y,z,v)), \
philpem@5 1243 (I[7] = (img)(x,_p1##y,z,v)), \
philpem@5 1244 (I[12] = (img)(x,y,z,v)), \
philpem@5 1245 (I[17] = (img)(x,_n1##y,z,v)), \
philpem@5 1246 (I[22] = (img)(x,_n2##y,z,v)), \
philpem@5 1247 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1248 (I[8] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1249 (I[13] = (img)(_n1##x,y,z,v)), \
philpem@5 1250 (I[18] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1251 (I[23] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1252 x+2>=(int)(img).width?(int)((img).width)-1:x+2); \
philpem@5 1253 x<=(int)(x1) && ((_n2##x<(int)((img).width) && ( \
philpem@5 1254 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1255 (I[9] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1256 (I[14] = (img)(_n2##x,y,z,v)), \
philpem@5 1257 (I[19] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1258 (I[24] = (img)(_n2##x,_n2##y,z,v)),1)) || \
philpem@5 1259 _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \
philpem@5 1260 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \
philpem@5 1261 I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \
philpem@5 1262 I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \
philpem@5 1263 I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \
philpem@5 1264 I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \
philpem@5 1265 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x)
philpem@5 1266
philpem@5 1267 #define cimg_for6x6(img,x,y,z,v,I) \
philpem@5 1268 cimg_for6((img).height,y) for (int x = 0, \
philpem@5 1269 _p2##x = 0, _p1##x = 0, \
philpem@5 1270 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
philpem@5 1271 _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
philpem@5 1272 _n3##x = (int)( \
philpem@5 1273 (I[0] = I[1] = I[2] = (img)(0,_p2##y,z,v)), \
philpem@5 1274 (I[6] = I[7] = I[8] = (img)(0,_p1##y,z,v)), \
philpem@5 1275 (I[12] = I[13] = I[14] = (img)(0,y,z,v)), \
philpem@5 1276 (I[18] = I[19] = I[20] = (img)(0,_n1##y,z,v)), \
philpem@5 1277 (I[24] = I[25] = I[26] = (img)(0,_n2##y,z,v)), \
philpem@5 1278 (I[30] = I[31] = I[32] = (img)(0,_n3##y,z,v)), \
philpem@5 1279 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1280 (I[9] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1281 (I[15] = (img)(_n1##x,y,z,v)), \
philpem@5 1282 (I[21] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1283 (I[27] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1284 (I[33] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1285 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1286 (I[10] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1287 (I[16] = (img)(_n2##x,y,z,v)), \
philpem@5 1288 (I[22] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1289 (I[28] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1290 (I[34] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1291 3>=(img).width?(int)((img).width)-1:3); \
philpem@5 1292 (_n3##x<(int)((img).width) && ( \
philpem@5 1293 (I[5] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1294 (I[11] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1295 (I[17] = (img)(_n3##x,y,z,v)), \
philpem@5 1296 (I[23] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1297 (I[29] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1298 (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
philpem@5 1299 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \
philpem@5 1300 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
philpem@5 1301 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
philpem@5 1302 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
philpem@5 1303 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
philpem@5 1304 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
philpem@5 1305 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
philpem@5 1306 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
philpem@5 1307
philpem@5 1308 #define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1309 cimg_for_in6((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \
philpem@5 1310 _p2##x = x-2<0?0:x-2, \
philpem@5 1311 _p1##x = x-1<0?0:x-1, \
philpem@5 1312 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
philpem@5 1313 _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
philpem@5 1314 _n3##x = (int)( \
philpem@5 1315 (I[0] = (img)(_p2##x,_p2##y,z,v)), \
philpem@5 1316 (I[6] = (img)(_p2##x,_p1##y,z,v)), \
philpem@5 1317 (I[12] = (img)(_p2##x,y,z,v)), \
philpem@5 1318 (I[18] = (img)(_p2##x,_n1##y,z,v)), \
philpem@5 1319 (I[24] = (img)(_p2##x,_n2##y,z,v)), \
philpem@5 1320 (I[30] = (img)(_p2##x,_n3##y,z,v)), \
philpem@5 1321 (I[1] = (img)(_p1##x,_p2##y,z,v)), \
philpem@5 1322 (I[7] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1323 (I[13] = (img)(_p1##x,y,z,v)), \
philpem@5 1324 (I[19] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1325 (I[25] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1326 (I[31] = (img)(_p1##x,_n3##y,z,v)), \
philpem@5 1327 (I[2] = (img)(x,_p2##y,z,v)), \
philpem@5 1328 (I[8] = (img)(x,_p1##y,z,v)), \
philpem@5 1329 (I[14] = (img)(x,y,z,v)), \
philpem@5 1330 (I[20] = (img)(x,_n1##y,z,v)), \
philpem@5 1331 (I[26] = (img)(x,_n2##y,z,v)), \
philpem@5 1332 (I[32] = (img)(x,_n3##y,z,v)), \
philpem@5 1333 (I[3] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1334 (I[9] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1335 (I[15] = (img)(_n1##x,y,z,v)), \
philpem@5 1336 (I[21] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1337 (I[27] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1338 (I[33] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1339 (I[4] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1340 (I[10] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1341 (I[16] = (img)(_n2##x,y,z,v)), \
philpem@5 1342 (I[22] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1343 (I[28] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1344 (I[34] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1345 x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
philpem@5 1346 x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
philpem@5 1347 (I[5] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1348 (I[11] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1349 (I[17] = (img)(_n3##x,y,z,v)), \
philpem@5 1350 (I[23] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1351 (I[29] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1352 (I[35] = (img)(_n3##x,_n3##y,z,v)),1)) || \
philpem@5 1353 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \
philpem@5 1354 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \
philpem@5 1355 I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \
philpem@5 1356 I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
philpem@5 1357 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
philpem@5 1358 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \
philpem@5 1359 I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
philpem@5 1360 _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
philpem@5 1361
philpem@5 1362 #define cimg_for7x7(img,x,y,z,v,I) \
philpem@5 1363 cimg_for7((img).height,y) for (int x = 0, \
philpem@5 1364 _p3##x = 0, _p2##x = 0, _p1##x = 0, \
philpem@5 1365 _n1##x = 1>=(img).width?(int)((img).width)-1:1, \
philpem@5 1366 _n2##x = 2>=(img).width?(int)((img).width)-1:2, \
philpem@5 1367 _n3##x = (int)( \
philpem@5 1368 (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
philpem@5 1369 (I[7] = I[8] = I[9] = I[10] = (img)(0,_p2##y,z,v)), \
philpem@5 1370 (I[14] = I[15] = I[16] = I[17] = (img)(0,_p1##y,z,v)), \
philpem@5 1371 (I[21] = I[22] = I[23] = I[24] = (img)(0,y,z,v)), \
philpem@5 1372 (I[28] = I[29] = I[30] = I[31] = (img)(0,_n1##y,z,v)), \
philpem@5 1373 (I[35] = I[36] = I[37] = I[38] = (img)(0,_n2##y,z,v)), \
philpem@5 1374 (I[42] = I[43] = I[44] = I[45] = (img)(0,_n3##y,z,v)), \
philpem@5 1375 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1376 (I[11] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1377 (I[18] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1378 (I[25] = (img)(_n1##x,y,z,v)), \
philpem@5 1379 (I[32] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1380 (I[39] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1381 (I[46] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1382 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1383 (I[12] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1384 (I[19] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1385 (I[26] = (img)(_n2##x,y,z,v)), \
philpem@5 1386 (I[33] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1387 (I[40] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1388 (I[47] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1389 3>=(img).width?(int)((img).width)-1:3); \
philpem@5 1390 (_n3##x<(int)((img).width) && ( \
philpem@5 1391 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1392 (I[13] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1393 (I[20] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1394 (I[27] = (img)(_n3##x,y,z,v)), \
philpem@5 1395 (I[34] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1396 (I[41] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1397 (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
philpem@5 1398 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \
philpem@5 1399 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
philpem@5 1400 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
philpem@5 1401 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
philpem@5 1402 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
philpem@5 1403 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
philpem@5 1404 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
philpem@5 1405 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
philpem@5 1406 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
philpem@5 1407
philpem@5 1408 #define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1409 cimg_for_in7((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1410 _p3##x = x-3<0?0:x-3, \
philpem@5 1411 _p2##x = x-2<0?0:x-2, \
philpem@5 1412 _p1##x = x-1<0?0:x-1, \
philpem@5 1413 _n1##x = x+1>=(int)(img).width?(int)((img).width)-1:x+1, \
philpem@5 1414 _n2##x = x+2>=(int)(img).width?(int)((img).width)-1:x+2, \
philpem@5 1415 _n3##x = (int)( \
philpem@5 1416 (I[0] = (img)(_p3##x,_p3##y,z,v)), \
philpem@5 1417 (I[7] = (img)(_p3##x,_p2##y,z,v)), \
philpem@5 1418 (I[14] = (img)(_p3##x,_p1##y,z,v)), \
philpem@5 1419 (I[21] = (img)(_p3##x,y,z,v)), \
philpem@5 1420 (I[28] = (img)(_p3##x,_n1##y,z,v)), \
philpem@5 1421 (I[35] = (img)(_p3##x,_n2##y,z,v)), \
philpem@5 1422 (I[42] = (img)(_p3##x,_n3##y,z,v)), \
philpem@5 1423 (I[1] = (img)(_p2##x,_p3##y,z,v)), \
philpem@5 1424 (I[8] = (img)(_p2##x,_p2##y,z,v)), \
philpem@5 1425 (I[15] = (img)(_p2##x,_p1##y,z,v)), \
philpem@5 1426 (I[22] = (img)(_p2##x,y,z,v)), \
philpem@5 1427 (I[29] = (img)(_p2##x,_n1##y,z,v)), \
philpem@5 1428 (I[36] = (img)(_p2##x,_n2##y,z,v)), \
philpem@5 1429 (I[43] = (img)(_p2##x,_n3##y,z,v)), \
philpem@5 1430 (I[2] = (img)(_p1##x,_p3##y,z,v)), \
philpem@5 1431 (I[9] = (img)(_p1##x,_p2##y,z,v)), \
philpem@5 1432 (I[16] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1433 (I[23] = (img)(_p1##x,y,z,v)), \
philpem@5 1434 (I[30] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1435 (I[37] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1436 (I[44] = (img)(_p1##x,_n3##y,z,v)), \
philpem@5 1437 (I[3] = (img)(x,_p3##y,z,v)), \
philpem@5 1438 (I[10] = (img)(x,_p2##y,z,v)), \
philpem@5 1439 (I[17] = (img)(x,_p1##y,z,v)), \
philpem@5 1440 (I[24] = (img)(x,y,z,v)), \
philpem@5 1441 (I[31] = (img)(x,_n1##y,z,v)), \
philpem@5 1442 (I[38] = (img)(x,_n2##y,z,v)), \
philpem@5 1443 (I[45] = (img)(x,_n3##y,z,v)), \
philpem@5 1444 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1445 (I[11] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1446 (I[18] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1447 (I[25] = (img)(_n1##x,y,z,v)), \
philpem@5 1448 (I[32] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1449 (I[39] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1450 (I[46] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1451 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1452 (I[12] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1453 (I[19] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1454 (I[26] = (img)(_n2##x,y,z,v)), \
philpem@5 1455 (I[33] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1456 (I[40] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1457 (I[47] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1458 x+3>=(int)(img).width?(int)((img).width)-1:x+3); \
philpem@5 1459 x<=(int)(x1) && ((_n3##x<(int)((img).width) && ( \
philpem@5 1460 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1461 (I[13] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1462 (I[20] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1463 (I[27] = (img)(_n3##x,y,z,v)), \
philpem@5 1464 (I[34] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1465 (I[41] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1466 (I[48] = (img)(_n3##x,_n3##y,z,v)),1)) || \
philpem@5 1467 _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \
philpem@5 1468 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \
philpem@5 1469 I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \
philpem@5 1470 I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \
philpem@5 1471 I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \
philpem@5 1472 I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \
philpem@5 1473 I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \
philpem@5 1474 I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \
philpem@5 1475 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x)
philpem@5 1476
philpem@5 1477 #define cimg_for8x8(img,x,y,z,v,I) \
philpem@5 1478 cimg_for8((img).height,y) for (int x = 0, \
philpem@5 1479 _p3##x = 0, _p2##x = 0, _p1##x = 0, \
philpem@5 1480 _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
philpem@5 1481 _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
philpem@5 1482 _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
philpem@5 1483 _n4##x = (int)( \
philpem@5 1484 (I[0] = I[1] = I[2] = I[3] = (img)(0,_p3##y,z,v)), \
philpem@5 1485 (I[8] = I[9] = I[10] = I[11] = (img)(0,_p2##y,z,v)), \
philpem@5 1486 (I[16] = I[17] = I[18] = I[19] = (img)(0,_p1##y,z,v)), \
philpem@5 1487 (I[24] = I[25] = I[26] = I[27] = (img)(0,y,z,v)), \
philpem@5 1488 (I[32] = I[33] = I[34] = I[35] = (img)(0,_n1##y,z,v)), \
philpem@5 1489 (I[40] = I[41] = I[42] = I[43] = (img)(0,_n2##y,z,v)), \
philpem@5 1490 (I[48] = I[49] = I[50] = I[51] = (img)(0,_n3##y,z,v)), \
philpem@5 1491 (I[56] = I[57] = I[58] = I[59] = (img)(0,_n4##y,z,v)), \
philpem@5 1492 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1493 (I[12] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1494 (I[20] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1495 (I[28] = (img)(_n1##x,y,z,v)), \
philpem@5 1496 (I[36] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1497 (I[44] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1498 (I[52] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1499 (I[60] = (img)(_n1##x,_n4##y,z,v)), \
philpem@5 1500 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1501 (I[13] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1502 (I[21] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1503 (I[29] = (img)(_n2##x,y,z,v)), \
philpem@5 1504 (I[37] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1505 (I[45] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1506 (I[53] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1507 (I[61] = (img)(_n2##x,_n4##y,z,v)), \
philpem@5 1508 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1509 (I[14] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1510 (I[22] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1511 (I[30] = (img)(_n3##x,y,z,v)), \
philpem@5 1512 (I[38] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1513 (I[46] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1514 (I[54] = (img)(_n3##x,_n3##y,z,v)), \
philpem@5 1515 (I[62] = (img)(_n3##x,_n4##y,z,v)), \
philpem@5 1516 4>=((img).width)?(int)((img).width)-1:4); \
philpem@5 1517 (_n4##x<(int)((img).width) && ( \
philpem@5 1518 (I[7] = (img)(_n4##x,_p3##y,z,v)), \
philpem@5 1519 (I[15] = (img)(_n4##x,_p2##y,z,v)), \
philpem@5 1520 (I[23] = (img)(_n4##x,_p1##y,z,v)), \
philpem@5 1521 (I[31] = (img)(_n4##x,y,z,v)), \
philpem@5 1522 (I[39] = (img)(_n4##x,_n1##y,z,v)), \
philpem@5 1523 (I[47] = (img)(_n4##x,_n2##y,z,v)), \
philpem@5 1524 (I[55] = (img)(_n4##x,_n3##y,z,v)), \
philpem@5 1525 (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
philpem@5 1526 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
philpem@5 1527 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
philpem@5 1528 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
philpem@5 1529 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
philpem@5 1530 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
philpem@5 1531 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
philpem@5 1532 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
philpem@5 1533 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
philpem@5 1534 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
philpem@5 1535 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
philpem@5 1536
philpem@5 1537 #define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1538 cimg_for_in8((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1539 _p3##x = x-3<0?0:x-3, \
philpem@5 1540 _p2##x = x-2<0?0:x-2, \
philpem@5 1541 _p1##x = x-1<0?0:x-1, \
philpem@5 1542 _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
philpem@5 1543 _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
philpem@5 1544 _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
philpem@5 1545 _n4##x = (int)( \
philpem@5 1546 (I[0] = (img)(_p3##x,_p3##y,z,v)), \
philpem@5 1547 (I[8] = (img)(_p3##x,_p2##y,z,v)), \
philpem@5 1548 (I[16] = (img)(_p3##x,_p1##y,z,v)), \
philpem@5 1549 (I[24] = (img)(_p3##x,y,z,v)), \
philpem@5 1550 (I[32] = (img)(_p3##x,_n1##y,z,v)), \
philpem@5 1551 (I[40] = (img)(_p3##x,_n2##y,z,v)), \
philpem@5 1552 (I[48] = (img)(_p3##x,_n3##y,z,v)), \
philpem@5 1553 (I[56] = (img)(_p3##x,_n4##y,z,v)), \
philpem@5 1554 (I[1] = (img)(_p2##x,_p3##y,z,v)), \
philpem@5 1555 (I[9] = (img)(_p2##x,_p2##y,z,v)), \
philpem@5 1556 (I[17] = (img)(_p2##x,_p1##y,z,v)), \
philpem@5 1557 (I[25] = (img)(_p2##x,y,z,v)), \
philpem@5 1558 (I[33] = (img)(_p2##x,_n1##y,z,v)), \
philpem@5 1559 (I[41] = (img)(_p2##x,_n2##y,z,v)), \
philpem@5 1560 (I[49] = (img)(_p2##x,_n3##y,z,v)), \
philpem@5 1561 (I[57] = (img)(_p2##x,_n4##y,z,v)), \
philpem@5 1562 (I[2] = (img)(_p1##x,_p3##y,z,v)), \
philpem@5 1563 (I[10] = (img)(_p1##x,_p2##y,z,v)), \
philpem@5 1564 (I[18] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1565 (I[26] = (img)(_p1##x,y,z,v)), \
philpem@5 1566 (I[34] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1567 (I[42] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1568 (I[50] = (img)(_p1##x,_n3##y,z,v)), \
philpem@5 1569 (I[58] = (img)(_p1##x,_n4##y,z,v)), \
philpem@5 1570 (I[3] = (img)(x,_p3##y,z,v)), \
philpem@5 1571 (I[11] = (img)(x,_p2##y,z,v)), \
philpem@5 1572 (I[19] = (img)(x,_p1##y,z,v)), \
philpem@5 1573 (I[27] = (img)(x,y,z,v)), \
philpem@5 1574 (I[35] = (img)(x,_n1##y,z,v)), \
philpem@5 1575 (I[43] = (img)(x,_n2##y,z,v)), \
philpem@5 1576 (I[51] = (img)(x,_n3##y,z,v)), \
philpem@5 1577 (I[59] = (img)(x,_n4##y,z,v)), \
philpem@5 1578 (I[4] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1579 (I[12] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1580 (I[20] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1581 (I[28] = (img)(_n1##x,y,z,v)), \
philpem@5 1582 (I[36] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1583 (I[44] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1584 (I[52] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1585 (I[60] = (img)(_n1##x,_n4##y,z,v)), \
philpem@5 1586 (I[5] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1587 (I[13] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1588 (I[21] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1589 (I[29] = (img)(_n2##x,y,z,v)), \
philpem@5 1590 (I[37] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1591 (I[45] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1592 (I[53] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1593 (I[61] = (img)(_n2##x,_n4##y,z,v)), \
philpem@5 1594 (I[6] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1595 (I[14] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1596 (I[22] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1597 (I[30] = (img)(_n3##x,y,z,v)), \
philpem@5 1598 (I[38] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1599 (I[46] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1600 (I[54] = (img)(_n3##x,_n3##y,z,v)), \
philpem@5 1601 (I[62] = (img)(_n3##x,_n4##y,z,v)), \
philpem@5 1602 x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
philpem@5 1603 x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
philpem@5 1604 (I[7] = (img)(_n4##x,_p3##y,z,v)), \
philpem@5 1605 (I[15] = (img)(_n4##x,_p2##y,z,v)), \
philpem@5 1606 (I[23] = (img)(_n4##x,_p1##y,z,v)), \
philpem@5 1607 (I[31] = (img)(_n4##x,y,z,v)), \
philpem@5 1608 (I[39] = (img)(_n4##x,_n1##y,z,v)), \
philpem@5 1609 (I[47] = (img)(_n4##x,_n2##y,z,v)), \
philpem@5 1610 (I[55] = (img)(_n4##x,_n3##y,z,v)), \
philpem@5 1611 (I[63] = (img)(_n4##x,_n4##y,z,v)),1)) || \
philpem@5 1612 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
philpem@5 1613 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \
philpem@5 1614 I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \
philpem@5 1615 I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \
philpem@5 1616 I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \
philpem@5 1617 I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \
philpem@5 1618 I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \
philpem@5 1619 I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \
philpem@5 1620 I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \
philpem@5 1621 _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
philpem@5 1622
philpem@5 1623 #define cimg_for9x9(img,x,y,z,v,I) \
philpem@5 1624 cimg_for9((img).height,y) for (int x = 0, \
philpem@5 1625 _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \
philpem@5 1626 _n1##x = 1>=((img).width)?(int)((img).width)-1:1, \
philpem@5 1627 _n2##x = 2>=((img).width)?(int)((img).width)-1:2, \
philpem@5 1628 _n3##x = 3>=((img).width)?(int)((img).width)-1:3, \
philpem@5 1629 _n4##x = (int)( \
philpem@5 1630 (I[0] = I[1] = I[2] = I[3] = I[4] = (img)(0,_p4##y,z,v)), \
philpem@5 1631 (I[9] = I[10] = I[11] = I[12] = I[13] = (img)(0,_p3##y,z,v)), \
philpem@5 1632 (I[18] = I[19] = I[20] = I[21] = I[22] = (img)(0,_p2##y,z,v)), \
philpem@5 1633 (I[27] = I[28] = I[29] = I[30] = I[31] = (img)(0,_p1##y,z,v)), \
philpem@5 1634 (I[36] = I[37] = I[38] = I[39] = I[40] = (img)(0,y,z,v)), \
philpem@5 1635 (I[45] = I[46] = I[47] = I[48] = I[49] = (img)(0,_n1##y,z,v)), \
philpem@5 1636 (I[54] = I[55] = I[56] = I[57] = I[58] = (img)(0,_n2##y,z,v)), \
philpem@5 1637 (I[63] = I[64] = I[65] = I[66] = I[67] = (img)(0,_n3##y,z,v)), \
philpem@5 1638 (I[72] = I[73] = I[74] = I[75] = I[76] = (img)(0,_n4##y,z,v)), \
philpem@5 1639 (I[5] = (img)(_n1##x,_p4##y,z,v)), \
philpem@5 1640 (I[14] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1641 (I[23] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1642 (I[32] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1643 (I[41] = (img)(_n1##x,y,z,v)), \
philpem@5 1644 (I[50] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1645 (I[59] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1646 (I[68] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1647 (I[77] = (img)(_n1##x,_n4##y,z,v)), \
philpem@5 1648 (I[6] = (img)(_n2##x,_p4##y,z,v)), \
philpem@5 1649 (I[15] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1650 (I[24] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1651 (I[33] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1652 (I[42] = (img)(_n2##x,y,z,v)), \
philpem@5 1653 (I[51] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1654 (I[60] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1655 (I[69] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1656 (I[78] = (img)(_n2##x,_n4##y,z,v)), \
philpem@5 1657 (I[7] = (img)(_n3##x,_p4##y,z,v)), \
philpem@5 1658 (I[16] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1659 (I[25] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1660 (I[34] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1661 (I[43] = (img)(_n3##x,y,z,v)), \
philpem@5 1662 (I[52] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1663 (I[61] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1664 (I[70] = (img)(_n3##x,_n3##y,z,v)), \
philpem@5 1665 (I[79] = (img)(_n3##x,_n4##y,z,v)), \
philpem@5 1666 4>=((img).width)?(int)((img).width)-1:4); \
philpem@5 1667 (_n4##x<(int)((img).width) && ( \
philpem@5 1668 (I[8] = (img)(_n4##x,_p4##y,z,v)), \
philpem@5 1669 (I[17] = (img)(_n4##x,_p3##y,z,v)), \
philpem@5 1670 (I[26] = (img)(_n4##x,_p2##y,z,v)), \
philpem@5 1671 (I[35] = (img)(_n4##x,_p1##y,z,v)), \
philpem@5 1672 (I[44] = (img)(_n4##x,y,z,v)), \
philpem@5 1673 (I[53] = (img)(_n4##x,_n1##y,z,v)), \
philpem@5 1674 (I[62] = (img)(_n4##x,_n2##y,z,v)), \
philpem@5 1675 (I[71] = (img)(_n4##x,_n3##y,z,v)), \
philpem@5 1676 (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
philpem@5 1677 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \
philpem@5 1678 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
philpem@5 1679 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
philpem@5 1680 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
philpem@5 1681 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
philpem@5 1682 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
philpem@5 1683 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
philpem@5 1684 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
philpem@5 1685 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
philpem@5 1686 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
philpem@5 1687 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
philpem@5 1688
philpem@5 1689 #define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,v,I) \
philpem@5 1690 cimg_for_in9((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1691 _p4##x = x-4<0?0:x-4, \
philpem@5 1692 _p3##x = x-3<0?0:x-3, \
philpem@5 1693 _p2##x = x-2<0?0:x-2, \
philpem@5 1694 _p1##x = x-1<0?0:x-1, \
philpem@5 1695 _n1##x = x+1>=(int)((img).width)?(int)((img).width)-1:x+1, \
philpem@5 1696 _n2##x = x+2>=(int)((img).width)?(int)((img).width)-1:x+2, \
philpem@5 1697 _n3##x = x+3>=(int)((img).width)?(int)((img).width)-1:x+3, \
philpem@5 1698 _n4##x = (int)( \
philpem@5 1699 (I[0] = (img)(_p4##x,_p4##y,z,v)), \
philpem@5 1700 (I[9] = (img)(_p4##x,_p3##y,z,v)), \
philpem@5 1701 (I[18] = (img)(_p4##x,_p2##y,z,v)), \
philpem@5 1702 (I[27] = (img)(_p4##x,_p1##y,z,v)), \
philpem@5 1703 (I[36] = (img)(_p4##x,y,z,v)), \
philpem@5 1704 (I[45] = (img)(_p4##x,_n1##y,z,v)), \
philpem@5 1705 (I[54] = (img)(_p4##x,_n2##y,z,v)), \
philpem@5 1706 (I[63] = (img)(_p4##x,_n3##y,z,v)), \
philpem@5 1707 (I[72] = (img)(_p4##x,_n4##y,z,v)), \
philpem@5 1708 (I[1] = (img)(_p3##x,_p4##y,z,v)), \
philpem@5 1709 (I[10] = (img)(_p3##x,_p3##y,z,v)), \
philpem@5 1710 (I[19] = (img)(_p3##x,_p2##y,z,v)), \
philpem@5 1711 (I[28] = (img)(_p3##x,_p1##y,z,v)), \
philpem@5 1712 (I[37] = (img)(_p3##x,y,z,v)), \
philpem@5 1713 (I[46] = (img)(_p3##x,_n1##y,z,v)), \
philpem@5 1714 (I[55] = (img)(_p3##x,_n2##y,z,v)), \
philpem@5 1715 (I[64] = (img)(_p3##x,_n3##y,z,v)), \
philpem@5 1716 (I[73] = (img)(_p3##x,_n4##y,z,v)), \
philpem@5 1717 (I[2] = (img)(_p2##x,_p4##y,z,v)), \
philpem@5 1718 (I[11] = (img)(_p2##x,_p3##y,z,v)), \
philpem@5 1719 (I[20] = (img)(_p2##x,_p2##y,z,v)), \
philpem@5 1720 (I[29] = (img)(_p2##x,_p1##y,z,v)), \
philpem@5 1721 (I[38] = (img)(_p2##x,y,z,v)), \
philpem@5 1722 (I[47] = (img)(_p2##x,_n1##y,z,v)), \
philpem@5 1723 (I[56] = (img)(_p2##x,_n2##y,z,v)), \
philpem@5 1724 (I[65] = (img)(_p2##x,_n3##y,z,v)), \
philpem@5 1725 (I[74] = (img)(_p2##x,_n4##y,z,v)), \
philpem@5 1726 (I[3] = (img)(_p1##x,_p4##y,z,v)), \
philpem@5 1727 (I[12] = (img)(_p1##x,_p3##y,z,v)), \
philpem@5 1728 (I[21] = (img)(_p1##x,_p2##y,z,v)), \
philpem@5 1729 (I[30] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1730 (I[39] = (img)(_p1##x,y,z,v)), \
philpem@5 1731 (I[48] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1732 (I[57] = (img)(_p1##x,_n2##y,z,v)), \
philpem@5 1733 (I[66] = (img)(_p1##x,_n3##y,z,v)), \
philpem@5 1734 (I[75] = (img)(_p1##x,_n4##y,z,v)), \
philpem@5 1735 (I[4] = (img)(x,_p4##y,z,v)), \
philpem@5 1736 (I[13] = (img)(x,_p3##y,z,v)), \
philpem@5 1737 (I[22] = (img)(x,_p2##y,z,v)), \
philpem@5 1738 (I[31] = (img)(x,_p1##y,z,v)), \
philpem@5 1739 (I[40] = (img)(x,y,z,v)), \
philpem@5 1740 (I[49] = (img)(x,_n1##y,z,v)), \
philpem@5 1741 (I[58] = (img)(x,_n2##y,z,v)), \
philpem@5 1742 (I[67] = (img)(x,_n3##y,z,v)), \
philpem@5 1743 (I[76] = (img)(x,_n4##y,z,v)), \
philpem@5 1744 (I[5] = (img)(_n1##x,_p4##y,z,v)), \
philpem@5 1745 (I[14] = (img)(_n1##x,_p3##y,z,v)), \
philpem@5 1746 (I[23] = (img)(_n1##x,_p2##y,z,v)), \
philpem@5 1747 (I[32] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1748 (I[41] = (img)(_n1##x,y,z,v)), \
philpem@5 1749 (I[50] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1750 (I[59] = (img)(_n1##x,_n2##y,z,v)), \
philpem@5 1751 (I[68] = (img)(_n1##x,_n3##y,z,v)), \
philpem@5 1752 (I[77] = (img)(_n1##x,_n4##y,z,v)), \
philpem@5 1753 (I[6] = (img)(_n2##x,_p4##y,z,v)), \
philpem@5 1754 (I[15] = (img)(_n2##x,_p3##y,z,v)), \
philpem@5 1755 (I[24] = (img)(_n2##x,_p2##y,z,v)), \
philpem@5 1756 (I[33] = (img)(_n2##x,_p1##y,z,v)), \
philpem@5 1757 (I[42] = (img)(_n2##x,y,z,v)), \
philpem@5 1758 (I[51] = (img)(_n2##x,_n1##y,z,v)), \
philpem@5 1759 (I[60] = (img)(_n2##x,_n2##y,z,v)), \
philpem@5 1760 (I[69] = (img)(_n2##x,_n3##y,z,v)), \
philpem@5 1761 (I[78] = (img)(_n2##x,_n4##y,z,v)), \
philpem@5 1762 (I[7] = (img)(_n3##x,_p4##y,z,v)), \
philpem@5 1763 (I[16] = (img)(_n3##x,_p3##y,z,v)), \
philpem@5 1764 (I[25] = (img)(_n3##x,_p2##y,z,v)), \
philpem@5 1765 (I[34] = (img)(_n3##x,_p1##y,z,v)), \
philpem@5 1766 (I[43] = (img)(_n3##x,y,z,v)), \
philpem@5 1767 (I[52] = (img)(_n3##x,_n1##y,z,v)), \
philpem@5 1768 (I[61] = (img)(_n3##x,_n2##y,z,v)), \
philpem@5 1769 (I[70] = (img)(_n3##x,_n3##y,z,v)), \
philpem@5 1770 (I[79] = (img)(_n3##x,_n4##y,z,v)), \
philpem@5 1771 x+4>=(int)((img).width)?(int)((img).width)-1:x+4); \
philpem@5 1772 x<=(int)(x1) && ((_n4##x<(int)((img).width) && ( \
philpem@5 1773 (I[8] = (img)(_n4##x,_p4##y,z,v)), \
philpem@5 1774 (I[17] = (img)(_n4##x,_p3##y,z,v)), \
philpem@5 1775 (I[26] = (img)(_n4##x,_p2##y,z,v)), \
philpem@5 1776 (I[35] = (img)(_n4##x,_p1##y,z,v)), \
philpem@5 1777 (I[44] = (img)(_n4##x,y,z,v)), \
philpem@5 1778 (I[53] = (img)(_n4##x,_n1##y,z,v)), \
philpem@5 1779 (I[62] = (img)(_n4##x,_n2##y,z,v)), \
philpem@5 1780 (I[71] = (img)(_n4##x,_n3##y,z,v)), \
philpem@5 1781 (I[80] = (img)(_n4##x,_n4##y,z,v)),1)) || \
philpem@5 1782 _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \
philpem@5 1783 I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \
philpem@5 1784 I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \
philpem@5 1785 I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], \
philpem@5 1786 I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \
philpem@5 1787 I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], \
philpem@5 1788 I[45] = I[46], I[46] = I[47], I[47] = I[48], I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], \
philpem@5 1789 I[54] = I[55], I[55] = I[56], I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], \
philpem@5 1790 I[63] = I[64], I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \
philpem@5 1791 I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], I[79] = I[80], \
philpem@5 1792 _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x)
philpem@5 1793
philpem@5 1794 #define cimg_for2x2x2(img,x,y,z,v,I) \
philpem@5 1795 cimg_for2((img).depth,z) cimg_for2((img).height,y) for (int x = 0, \
philpem@5 1796 _n1##x = (int)( \
philpem@5 1797 (I[0] = (img)(0,y,z,v)), \
philpem@5 1798 (I[2] = (img)(0,_n1##y,z,v)), \
philpem@5 1799 (I[4] = (img)(0,y,_n1##z,v)), \
philpem@5 1800 (I[6] = (img)(0,_n1##y,_n1##z,v)), \
philpem@5 1801 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 1802 (_n1##x<(int)((img).width) && ( \
philpem@5 1803 (I[1] = (img)(_n1##x,y,z,v)), \
philpem@5 1804 (I[3] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1805 (I[5] = (img)(_n1##x,y,_n1##z,v)), \
philpem@5 1806 (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
philpem@5 1807 x==--_n1##x; \
philpem@5 1808 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
philpem@5 1809 ++x, ++_n1##x)
philpem@5 1810
philpem@5 1811 #define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
philpem@5 1812 cimg_for_in2((img).depth,z0,z1,z) cimg_for_in2((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1813 _n1##x = (int)( \
philpem@5 1814 (I[0] = (img)(x,y,z,v)), \
philpem@5 1815 (I[2] = (img)(x,_n1##y,z,v)), \
philpem@5 1816 (I[4] = (img)(x,y,_n1##z,v)), \
philpem@5 1817 (I[6] = (img)(x,_n1##y,_n1##z,v)), \
philpem@5 1818 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
philpem@5 1819 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
philpem@5 1820 (I[1] = (img)(_n1##x,y,z,v)), \
philpem@5 1821 (I[3] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1822 (I[5] = (img)(_n1##x,y,_n1##z,v)), \
philpem@5 1823 (I[7] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
philpem@5 1824 x==--_n1##x); \
philpem@5 1825 I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \
philpem@5 1826 ++x, ++_n1##x)
philpem@5 1827
philpem@5 1828 #define cimg_for3x3x3(img,x,y,z,v,I) \
philpem@5 1829 cimg_for3((img).depth,z) cimg_for3((img).height,y) for (int x = 0, \
philpem@5 1830 _p1##x = 0, \
philpem@5 1831 _n1##x = (int)( \
philpem@5 1832 (I[0] = I[1] = (img)(0,_p1##y,_p1##z,v)), \
philpem@5 1833 (I[3] = I[4] = (img)(0,y,_p1##z,v)), \
philpem@5 1834 (I[6] = I[7] = (img)(0,_n1##y,_p1##z,v)), \
philpem@5 1835 (I[9] = I[10] = (img)(0,_p1##y,z,v)), \
philpem@5 1836 (I[12] = I[13] = (img)(0,y,z,v)), \
philpem@5 1837 (I[15] = I[16] = (img)(0,_n1##y,z,v)), \
philpem@5 1838 (I[18] = I[19] = (img)(0,_p1##y,_n1##z,v)), \
philpem@5 1839 (I[21] = I[22] = (img)(0,y,_n1##z,v)), \
philpem@5 1840 (I[24] = I[25] = (img)(0,_n1##y,_n1##z,v)), \
philpem@5 1841 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 1842 (_n1##x<(int)((img).width) && ( \
philpem@5 1843 (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
philpem@5 1844 (I[5] = (img)(_n1##x,y,_p1##z,v)), \
philpem@5 1845 (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
philpem@5 1846 (I[11] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1847 (I[14] = (img)(_n1##x,y,z,v)), \
philpem@5 1848 (I[17] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1849 (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
philpem@5 1850 (I[23] = (img)(_n1##x,y,_n1##z,v)), \
philpem@5 1851 (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
philpem@5 1852 x==--_n1##x; \
philpem@5 1853 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
philpem@5 1854 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
philpem@5 1855 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
philpem@5 1856 _p1##x = x++, ++_n1##x)
philpem@5 1857
philpem@5 1858 #define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,v,I) \
philpem@5 1859 cimg_for_in3((img).depth,z0,z1,z) cimg_for_in3((img).height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \
philpem@5 1860 _p1##x = x-1<0?0:x-1, \
philpem@5 1861 _n1##x = (int)( \
philpem@5 1862 (I[0] = (img)(_p1##x,_p1##y,_p1##z,v)), \
philpem@5 1863 (I[3] = (img)(_p1##x,y,_p1##z,v)), \
philpem@5 1864 (I[6] = (img)(_p1##x,_n1##y,_p1##z,v)), \
philpem@5 1865 (I[9] = (img)(_p1##x,_p1##y,z,v)), \
philpem@5 1866 (I[12] = (img)(_p1##x,y,z,v)), \
philpem@5 1867 (I[15] = (img)(_p1##x,_n1##y,z,v)), \
philpem@5 1868 (I[18] = (img)(_p1##x,_p1##y,_n1##z,v)), \
philpem@5 1869 (I[21] = (img)(_p1##x,y,_n1##z,v)), \
philpem@5 1870 (I[24] = (img)(_p1##x,_n1##y,_n1##z,v)), \
philpem@5 1871 (I[1] = (img)(x,_p1##y,_p1##z,v)), \
philpem@5 1872 (I[4] = (img)(x,y,_p1##z,v)), \
philpem@5 1873 (I[7] = (img)(x,_n1##y,_p1##z,v)), \
philpem@5 1874 (I[10] = (img)(x,_p1##y,z,v)), \
philpem@5 1875 (I[13] = (img)(x,y,z,v)), \
philpem@5 1876 (I[16] = (img)(x,_n1##y,z,v)), \
philpem@5 1877 (I[19] = (img)(x,_p1##y,_n1##z,v)), \
philpem@5 1878 (I[22] = (img)(x,y,_n1##z,v)), \
philpem@5 1879 (I[25] = (img)(x,_n1##y,_n1##z,v)), \
philpem@5 1880 x+1>=(int)(img).width?(int)((img).width)-1:x+1); \
philpem@5 1881 x<=(int)(x1) && ((_n1##x<(int)((img).width) && ( \
philpem@5 1882 (I[2] = (img)(_n1##x,_p1##y,_p1##z,v)), \
philpem@5 1883 (I[5] = (img)(_n1##x,y,_p1##z,v)), \
philpem@5 1884 (I[8] = (img)(_n1##x,_n1##y,_p1##z,v)), \
philpem@5 1885 (I[11] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 1886 (I[14] = (img)(_n1##x,y,z,v)), \
philpem@5 1887 (I[17] = (img)(_n1##x,_n1##y,z,v)), \
philpem@5 1888 (I[20] = (img)(_n1##x,_p1##y,_n1##z,v)), \
philpem@5 1889 (I[23] = (img)(_n1##x,y,_n1##z,v)), \
philpem@5 1890 (I[26] = (img)(_n1##x,_n1##y,_n1##z,v)),1)) || \
philpem@5 1891 x==--_n1##x); \
philpem@5 1892 I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \
philpem@5 1893 I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \
philpem@5 1894 I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \
philpem@5 1895 _p1##x = x++, ++_n1##x)
philpem@5 1896
philpem@5 1897 /*------------------------------------------------
philpem@5 1898 #
philpem@5 1899 #
philpem@5 1900 # Definition of the cimg_library:: namespace
philpem@5 1901 #
philpem@5 1902 #
philpem@5 1903 -------------------------------------------------*/
philpem@5 1904 //! This namespace encompasses all classes and functions of the %CImg library.
philpem@5 1905 /**
philpem@5 1906 This namespace is defined to avoid functions and class names collisions
philpem@5 1907 that could happen with the include of other C++ header files.
philpem@5 1908 Anyway, it should not happen often and you should reasonnably start most of your
philpem@5 1909 %CImg-based programs with
philpem@5 1910 \code
philpem@5 1911 #include "CImg.h"
philpem@5 1912 using namespace cimg_library;
philpem@5 1913 \endcode
philpem@5 1914 to simplify the declaration of %CImg Library variables afterwards.
philpem@5 1915 **/
philpem@5 1916 namespace cimg_library {
philpem@5 1917
philpem@5 1918 // Declare the only four classes of the CImg Library.
philpem@5 1919 //
philpem@5 1920 template<typename T=float> struct CImg;
philpem@5 1921 template<typename T=float> struct CImgList;
philpem@5 1922 struct CImgDisplay;
philpem@5 1923 struct CImgException;
philpem@5 1924
philpem@5 1925 // (Pre)declare the cimg namespace.
philpem@5 1926 // This is not the complete namespace declaration. It only contains some
philpem@5 1927 // necessary stuffs to ensure a correct declaration order of classes and functions
philpem@5 1928 // defined afterwards.
philpem@5 1929 //
philpem@5 1930 namespace cimg {
philpem@5 1931
philpem@5 1932 #ifdef cimg_use_vt100
philpem@5 1933 const char t_normal[] = { 0x1b,'[','0',';','0',';','0','m','\0' };
philpem@5 1934 const char t_red[] = { 0x1b,'[','4',';','3','1',';','5','9','m','\0' };
philpem@5 1935 const char t_bold[] = { 0x1b,'[','1','m','\0' };
philpem@5 1936 const char t_purple[] = { 0x1b,'[','0',';','3','5',';','5','9','m','\0' };
philpem@5 1937 const char t_green[] = { 0x1b,'[','0',';','3','2',';','5','9','m','\0' };
philpem@5 1938 #else
philpem@5 1939 const char t_normal[] = { '\0' };
philpem@5 1940 const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal,
philpem@5 1941 *const t_purple = cimg::t_normal, *const t_green = cimg::t_normal;
philpem@5 1942 #endif
philpem@5 1943
philpem@5 1944 inline void info();
philpem@5 1945
philpem@5 1946 //! Get/set the current CImg exception mode.
philpem@5 1947 /**
philpem@5 1948 The way error messages are handled by CImg can be changed dynamically, using this function.
philpem@5 1949 Possible values are :
philpem@5 1950 - 0 to hide debug messages (quiet mode, but exceptions are still thrown).
philpem@5 1951 - 1 to display debug messages on standard error (console).
philpem@5 1952 - 2 to display debug messages in modal windows (default behavior).
philpem@5 1953 - 3 to do as 1 + add extra warnings (may slow down the code !).
philpem@5 1954 - 4 to do as 2 + add extra warnings (may slow down the code !).
philpem@5 1955 **/
philpem@5 1956 inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; }
philpem@5 1957
philpem@5 1958 inline int dialog(const char *title, const char *msg, const char *button1_txt="OK",
philpem@5 1959 const char *button2_txt=0, const char *button3_txt=0,
philpem@5 1960 const char *button4_txt=0, const char *button5_txt=0,
philpem@5 1961 const char *button6_txt=0, const bool centering=false);
philpem@5 1962 }
philpem@5 1963
philpem@5 1964 /*----------------------------------------------
philpem@5 1965 #
philpem@5 1966 # Definition of the CImgException structures
philpem@5 1967 #
philpem@5 1968 ----------------------------------------------*/
philpem@5 1969 //! Instances of this class are thrown when errors occur during a %CImg library function call.
philpem@5 1970 /**
philpem@5 1971 \section ex1 Overview
philpem@5 1972
philpem@5 1973 CImgException is the base class of %CImg exceptions.
philpem@5 1974 Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call.
philpem@5 1975 CImgException is seldom thrown itself. Children classes that specify the kind of error encountered
philpem@5 1976 are generally used instead. These sub-classes are :
philpem@5 1977
philpem@5 1978 - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not
philpem@5 1979 correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example
philpem@5 1980 below will throw a \a CImgInstanceException.
philpem@5 1981 \code
philpem@5 1982 CImg<float> img; // Construct an empty image.
philpem@5 1983 img.blur(10); // Try to blur the image.
philpem@5 1984 \endcode
philpem@5 1985
philpem@5 1986 - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct.
philpem@5 1987 Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values.
philpem@5 1988 The example below will throw a \a CImgArgumentException.
philpem@5 1989 \code
philpem@5 1990 CImg<float> img(100,100,1,3); // Define a 100x100 color image with float pixels.
philpem@5 1991 img = 0; // Try to fill pixels from the 0 pointer (invalid argument to operator=() ).
philpem@5 1992 \endcode
philpem@5 1993
philpem@5 1994 - \b CImgIOException : Thrown when an error occured when trying to load or save image files.
philpem@5 1995 The example below will throw a \a CImgIOException.
philpem@5 1996 \code
philpem@5 1997 CImg<float> img("file_doesnt_exist.jpg"); // Try to load a file that doesn't exist.
philpem@5 1998 \endcode
philpem@5 1999
philpem@5 2000 - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window.
philpem@5 2001 This exception is thrown when image display request cannot be satisfied.
philpem@5 2002
philpem@5 2003 The parent class CImgException may be thrown itself when errors that cannot be classified in one of
philpem@5 2004 the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally
philpem@5 2005 reserved to %CImg Library functions.
philpem@5 2006 \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple
philpem@5 2007 subclasses of CImgException and are thus not detailled more in this reference documentation.
philpem@5 2008
philpem@5 2009 \section ex2 Exception handling
philpem@5 2010
philpem@5 2011 When an error occurs, the %CImg Library first displays the error in a modal window.
philpem@5 2012 Then, it throws an instance of the corresponding exception class, generally leading the program to stop
philpem@5 2013 (this is the default behavior).
philpem@5 2014 You can bypass this default behavior by handling the exceptions yourself,
philpem@5 2015 using a code block <tt>try { ... } catch() { ... }</tt>.
philpem@5 2016 In this case, you can avoid the apparition of the modal window, by
philpem@5 2017 defining the environment variable <tt>cimg_debug</tt> to 0 before including the %CImg header file.
philpem@5 2018 The example below shows how to cleanly handle %CImg Library exceptions :
philpem@5 2019 \code
philpem@5 2020 #define cimg_debug 0 // Disable modal window in CImg exceptions.
philpem@5 2021 #define "CImg.h"
philpem@5 2022 int main() {
philpem@5 2023 try {
philpem@5 2024 ...; // Here, do what you want.
philpem@5 2025 }
philpem@5 2026 catch (CImgInstanceException &e) {
philpem@5 2027 std::fprintf(stderr,"CImg Library Error : %s",e.message); // Display your own error message
philpem@5 2028 ... // Do what you want now.
philpem@5 2029 }
philpem@5 2030 }
philpem@5 2031 \endcode
philpem@5 2032 **/
philpem@5 2033 struct CImgException {
philpem@5 2034 #define _cimg_exception_err(etype,disp_flag) \
philpem@5 2035 cimg_std::va_list ap; va_start(ap,format); cimg_std::vsprintf(message,format,ap); va_end(ap); \
philpem@5 2036 switch (cimg::exception_mode()) { \
philpem@5 2037 case 0 : break; \
philpem@5 2038 case 2 : case 4 : try { cimg::dialog(etype,message,"Abort"); } catch (CImgException&) { \
philpem@5 2039 cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
philpem@5 2040 } break; \
philpem@5 2041 default : cimg_std::fprintf(cimg_stdout,"\n%s# %s%s :\n%s\n\n",cimg::t_red,etype,cimg::t_normal,message); \
philpem@5 2042 } \
philpem@5 2043 if (cimg::exception_mode()>=3) cimg_library::cimg::info();
philpem@5 2044
philpem@5 2045 char message[1024]; //!< Message associated with the error that thrown the exception.
philpem@5 2046 CImgException() { message[0]='\0'; }
philpem@5 2047 CImgException(const char *format, ...) { _cimg_exception_err("CImgException",true); }
philpem@5 2048 };
philpem@5 2049
philpem@5 2050 // The \ref CImgInstanceException class is used to throw an exception related
philpem@5 2051 // to a non suitable instance encountered in a library function call.
philpem@5 2052 struct CImgInstanceException: public CImgException {
philpem@5 2053 CImgInstanceException(const char *format, ...) { _cimg_exception_err("CImgInstanceException",true); }
philpem@5 2054 };
philpem@5 2055
philpem@5 2056 // The \ref CImgArgumentException class is used to throw an exception related
philpem@5 2057 // to invalid arguments encountered in a library function call.
philpem@5 2058 struct CImgArgumentException: public CImgException {
philpem@5 2059 CImgArgumentException(const char *format, ...) { _cimg_exception_err("CImgArgumentException",true); }
philpem@5 2060 };
philpem@5 2061
philpem@5 2062 // The \ref CImgIOException class is used to throw an exception related
philpem@5 2063 // to Input/Output file problems encountered in a library function call.
philpem@5 2064 struct CImgIOException: public CImgException {
philpem@5 2065 CImgIOException(const char *format, ...) { _cimg_exception_err("CImgIOException",true); }
philpem@5 2066 };
philpem@5 2067
philpem@5 2068 // The CImgDisplayException class is used to throw an exception related to display problems
philpem@5 2069 // encountered in a library function call.
philpem@5 2070 struct CImgDisplayException: public CImgException {
philpem@5 2071 CImgDisplayException(const char *format, ...) { _cimg_exception_err("CImgDisplayException",false); }
philpem@5 2072 };
philpem@5 2073
philpem@5 2074 // The CImgWarningException class is used to throw an exception for warnings
philpem@5 2075 // encountered in a library function call.
philpem@5 2076 struct CImgWarningException: public CImgException {
philpem@5 2077 CImgWarningException(const char *format, ...) { _cimg_exception_err("CImgWarningException",false); }
philpem@5 2078 };
philpem@5 2079
philpem@5 2080 /*-------------------------------------
philpem@5 2081 #
philpem@5 2082 # Definition of the namespace 'cimg'
philpem@5 2083 #
philpem@5 2084 --------------------------------------*/
philpem@5 2085 //! Namespace that encompasses \a low-level functions and variables of the %CImg Library.
philpem@5 2086 /**
philpem@5 2087 Most of the functions and variables within this namespace are used by the library for low-level processing.
philpem@5 2088 Nevertheless, documented variables and functions of this namespace may be used safely in your own source code.
philpem@5 2089
philpem@5 2090 \warning Never write <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the
philpem@5 2091 <tt>cimg::</tt> namespace have prototypes similar to standard C functions that could defined in the global namespace <tt>::</tt>.
philpem@5 2092 **/
philpem@5 2093 namespace cimg {
philpem@5 2094
philpem@5 2095 // Define the traits that will be used to determine the best data type to work with.
philpem@5 2096 //
philpem@5 2097 template<typename T> struct type {
philpem@5 2098 static const char* string() {
philpem@5 2099 static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24",
philpem@5 2100 "unknown32", "unknown40", "unknown48", "unknown56",
philpem@5 2101 "unknown64", "unknown72", "unknown80", "unknown88",
philpem@5 2102 "unknown96", "unknown104", "unknown112", "unknown120",
philpem@5 2103 "unknown128" };
philpem@5 2104 return s[(sizeof(T)<17)?sizeof(T):0];
philpem@5 2105 }
philpem@5 2106 static bool is_float() { return false; }
philpem@5 2107 static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); }
philpem@5 2108 static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); }
philpem@5 2109 static const char* format() { return "%s"; }
philpem@5 2110 static const char* format(const T val) { static const char *s = "unknown"; return s; }
philpem@5 2111 };
philpem@5 2112
philpem@5 2113 template<> struct type<bool> {
philpem@5 2114 static const char* string() { static const char *const s = "bool"; return s; }
philpem@5 2115 static bool is_float() { return false; }
philpem@5 2116 static bool min() { return false; }
philpem@5 2117 static bool max() { return true; }
philpem@5 2118 static const char* format() { return "%s"; }
philpem@5 2119 static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
philpem@5 2120 };
philpem@5 2121
philpem@5 2122 template<> struct type<unsigned char> {
philpem@5 2123 static const char* string() { static const char *const s = "unsigned char"; return s; }
philpem@5 2124 static bool is_float() { return false; }
philpem@5 2125 static unsigned char min() { return 0; }
philpem@5 2126 static unsigned char max() { return (unsigned char)~0U; }
philpem@5 2127 static const char* format() { return "%u"; }
philpem@5 2128 static unsigned int format(const unsigned char val) { return (unsigned int)val; }
philpem@5 2129 };
philpem@5 2130
philpem@5 2131 template<> struct type<char> {
philpem@5 2132 static const char* string() { static const char *const s = "char"; return s; }
philpem@5 2133 static bool is_float() { return false; }
philpem@5 2134 static char min() { return (char)(-1L<<(8*sizeof(char)-1)); }
philpem@5 2135 static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); }
philpem@5 2136 static const char* format() { return "%d"; }
philpem@5 2137 static int format(const char val) { return (int)val; }
philpem@5 2138 };
philpem@5 2139
philpem@5 2140 template<> struct type<signed char> {
philpem@5 2141 static const char* string() { static const char *const s = "signed char"; return s; }
philpem@5 2142 static bool is_float() { return false; }
philpem@5 2143 static signed char min() { return (signed char)(-1L<<(8*sizeof(signed char)-1)); }
philpem@5 2144 static signed char max() { return ~((signed char)(-1L<<(8*sizeof(signed char)-1))); }
philpem@5 2145 static const char* format() { return "%d"; }
philpem@5 2146 static unsigned int format(const signed char val) { return (int)val; }
philpem@5 2147 };
philpem@5 2148
philpem@5 2149 template<> struct type<unsigned short> {
philpem@5 2150 static const char* string() { static const char *const s = "unsigned short"; return s; }
philpem@5 2151 static bool is_float() { return false; }
philpem@5 2152 static unsigned short min() { return 0; }
philpem@5 2153 static unsigned short max() { return (unsigned short)~0U; }
philpem@5 2154 static const char* format() { return "%u"; }
philpem@5 2155 static unsigned int format(const unsigned short val) { return (unsigned int)val; }
philpem@5 2156 };
philpem@5 2157
philpem@5 2158 template<> struct type<short> {
philpem@5 2159 static const char* string() { static const char *const s = "short"; return s; }
philpem@5 2160 static bool is_float() { return false; }
philpem@5 2161 static short min() { return (short)(-1L<<(8*sizeof(short)-1)); }
philpem@5 2162 static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); }
philpem@5 2163 static const char* format() { return "%d"; }
philpem@5 2164 static int format(const short val) { return (int)val; }
philpem@5 2165 };
philpem@5 2166
philpem@5 2167 template<> struct type<unsigned int> {
philpem@5 2168 static const char* string() { static const char *const s = "unsigned int"; return s; }
philpem@5 2169 static bool is_float() { return false; }
philpem@5 2170 static unsigned int min() { return 0; }
philpem@5 2171 static unsigned int max() { return (unsigned int)~0U; }
philpem@5 2172 static const char* format() { return "%u"; }
philpem@5 2173 static unsigned int format(const unsigned int val) { return val; }
philpem@5 2174 };
philpem@5 2175
philpem@5 2176 template<> struct type<int> {
philpem@5 2177 static const char* string() { static const char *const s = "int"; return s; }
philpem@5 2178 static bool is_float() { return false; }
philpem@5 2179 static int min() { return (int)(-1L<<(8*sizeof(int)-1)); }
philpem@5 2180 static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); }
philpem@5 2181 static const char* format() { return "%d"; }
philpem@5 2182 static int format(const int val) { return val; }
philpem@5 2183 };
philpem@5 2184
philpem@5 2185 template<> struct type<unsigned long> {
philpem@5 2186 static const char* string() { static const char *const s = "unsigned long"; return s; }
philpem@5 2187 static bool is_float() { return false; }
philpem@5 2188 static unsigned long min() { return 0; }
philpem@5 2189 static unsigned long max() { return (unsigned long)~0UL; }
philpem@5 2190 static const char* format() { return "%lu"; }
philpem@5 2191 static unsigned long format(const unsigned long val) { return val; }
philpem@5 2192 };
philpem@5 2193
philpem@5 2194 template<> struct type<long> {
philpem@5 2195 static const char* string() { static const char *const s = "long"; return s; }
philpem@5 2196 static bool is_float() { return false; }
philpem@5 2197 static long min() { return (long)(-1L<<(8*sizeof(long)-1)); }
philpem@5 2198 static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); }
philpem@5 2199 static const char* format() { return "%ld"; }
philpem@5 2200 static long format(const long val) { return val; }
philpem@5 2201 };
philpem@5 2202
philpem@5 2203 template<> struct type<float> {
philpem@5 2204 static const char* string() { static const char *const s = "float"; return s; }
philpem@5 2205 static bool is_float() { return true; }
philpem@5 2206 static float min() { return -3.4E38f; }
philpem@5 2207 static float max() { return 3.4E38f; }
philpem@5 2208 static const char* format() { return "%g"; }
philpem@5 2209 static double format(const float val) { return (double)val; }
philpem@5 2210 };
philpem@5 2211
philpem@5 2212 template<> struct type<double> {
philpem@5 2213 static const char* string() { static const char *const s = "double"; return s; }
philpem@5 2214 static bool is_float() { return true; }
philpem@5 2215 static double min() { return -1.7E308; }
philpem@5 2216 static double max() { return 1.7E308; }
philpem@5 2217 static const char* format() { return "%g"; }
philpem@5 2218 static double format(const double val) { return val; }
philpem@5 2219 };
philpem@5 2220
philpem@5 2221 template<typename T, typename t> struct superset { typedef T type; };
philpem@5 2222 template<> struct superset<bool,unsigned char> { typedef unsigned char type; };
philpem@5 2223 template<> struct superset<bool,char> { typedef char type; };
philpem@5 2224 template<> struct superset<bool,signed char> { typedef signed char type; };
philpem@5 2225 template<> struct superset<bool,unsigned short> { typedef unsigned short type; };
philpem@5 2226 template<> struct superset<bool,short> { typedef short type; };
philpem@5 2227 template<> struct superset<bool,unsigned int> { typedef unsigned int type; };
philpem@5 2228 template<> struct superset<bool,int> { typedef int type; };
philpem@5 2229 template<> struct superset<bool,unsigned long> { typedef unsigned long type; };
philpem@5 2230 template<> struct superset<bool,long> { typedef long type; };
philpem@5 2231 template<> struct superset<bool,float> { typedef float type; };
philpem@5 2232 template<> struct superset<bool,double> { typedef double type; };
philpem@5 2233 template<> struct superset<unsigned char,char> { typedef short type; };
philpem@5 2234 template<> struct superset<unsigned char,signed char> { typedef short type; };
philpem@5 2235 template<> struct superset<unsigned char,unsigned short> { typedef unsigned short type; };
philpem@5 2236 template<> struct superset<unsigned char,short> { typedef short type; };
philpem@5 2237 template<> struct superset<unsigned char,unsigned int> { typedef unsigned int type; };
philpem@5 2238 template<> struct superset<unsigned char,int> { typedef int type; };
philpem@5 2239 template<> struct superset<unsigned char,unsigned long> { typedef unsigned long type; };
philpem@5 2240 template<> struct superset<unsigned char,long> { typedef long type; };
philpem@5 2241 template<> struct superset<unsigned char,float> { typedef float type; };
philpem@5 2242 template<> struct superset<unsigned char,double> { typedef double type; };
philpem@5 2243 template<> struct superset<signed char,unsigned char> { typedef short type; };
philpem@5 2244 template<> struct superset<signed char,char> { typedef short type; };
philpem@5 2245 template<> struct superset<signed char,unsigned short> { typedef int type; };
philpem@5 2246 template<> struct superset<signed char,short> { typedef short type; };
philpem@5 2247 template<> struct superset<signed char,unsigned int> { typedef long type; };
philpem@5 2248 template<> struct superset<signed char,int> { typedef int type; };
philpem@5 2249 template<> struct superset<signed char,unsigned long> { typedef long type; };
philpem@5 2250 template<> struct superset<signed char,long> { typedef long type; };
philpem@5 2251 template<> struct superset<signed char,float> { typedef float type; };
philpem@5 2252 template<> struct superset<signed char,double> { typedef double type; };
philpem@5 2253 template<> struct superset<char,unsigned char> { typedef short type; };
philpem@5 2254 template<> struct superset<char,signed char> { typedef short type; };
philpem@5 2255 template<> struct superset<char,unsigned short> { typedef int type; };
philpem@5 2256 template<> struct superset<char,short> { typedef short type; };
philpem@5 2257 template<> struct superset<char,unsigned int> { typedef long type; };
philpem@5 2258 template<> struct superset<char,int> { typedef int type; };
philpem@5 2259 template<> struct superset<char,unsigned long> { typedef long type; };
philpem@5 2260 template<> struct superset<char,long> { typedef long type; };
philpem@5 2261 template<> struct superset<char,float> { typedef float type; };
philpem@5 2262 template<> struct superset<char,double> { typedef double type; };
philpem@5 2263 template<> struct superset<unsigned short,char> { typedef int type; };
philpem@5 2264 template<> struct superset<unsigned short,signed char> { typedef int type; };
philpem@5 2265 template<> struct superset<unsigned short,short> { typedef int type; };
philpem@5 2266 template<> struct superset<unsigned short,unsigned int> { typedef unsigned int type; };
philpem@5 2267 template<> struct superset<unsigned short,int> { typedef int type; };
philpem@5 2268 template<> struct superset<unsigned short,unsigned long> { typedef unsigned long type; };
philpem@5 2269 template<> struct superset<unsigned short,long> { typedef long type; };
philpem@5 2270 template<> struct superset<unsigned short,float> { typedef float type; };
philpem@5 2271 template<> struct superset<unsigned short,double> { typedef double type; };
philpem@5 2272 template<> struct superset<short,unsigned short> { typedef int type; };
philpem@5 2273 template<> struct superset<short,unsigned int> { typedef long type; };
philpem@5 2274 template<> struct superset<short,int> { typedef int type; };
philpem@5 2275 template<> struct superset<short,unsigned long> { typedef long type; };
philpem@5 2276 template<> struct superset<short,long> { typedef long type; };
philpem@5 2277 template<> struct superset<short,float> { typedef float type; };
philpem@5 2278 template<> struct superset<short,double> { typedef double type; };
philpem@5 2279 template<> struct superset<unsigned int,char> { typedef long type; };
philpem@5 2280 template<> struct superset<unsigned int,signed char> { typedef long type; };
philpem@5 2281 template<> struct superset<unsigned int,short> { typedef long type; };
philpem@5 2282 template<> struct superset<unsigned int,int> { typedef long type; };
philpem@5 2283 template<> struct superset<unsigned int,unsigned long> { typedef unsigned long type; };
philpem@5 2284 template<> struct superset<unsigned int,long> { typedef long type; };
philpem@5 2285 template<> struct superset<unsigned int,float> { typedef float type; };
philpem@5 2286 template<> struct superset<unsigned int,double> { typedef double type; };
philpem@5 2287 template<> struct superset<int,unsigned int> { typedef long type; };
philpem@5 2288 template<> struct superset<int,unsigned long> { typedef long type; };
philpem@5 2289 template<> struct superset<int,long> { typedef long type; };
philpem@5 2290 template<> struct superset<int,float> { typedef float type; };
philpem@5 2291 template<> struct superset<int,double> { typedef double type; };
philpem@5 2292 template<> struct superset<unsigned long,char> { typedef long type; };
philpem@5 2293 template<> struct superset<unsigned long,signed char> { typedef long type; };
philpem@5 2294 template<> struct superset<unsigned long,short> { typedef long type; };
philpem@5 2295 template<> struct superset<unsigned long,int> { typedef long type; };
philpem@5 2296 template<> struct superset<unsigned long,long> { typedef long type; };
philpem@5 2297 template<> struct superset<unsigned long,float> { typedef float type; };
philpem@5 2298 template<> struct superset<unsigned long,double> { typedef double type; };
philpem@5 2299 template<> struct superset<long,float> { typedef float type; };
philpem@5 2300 template<> struct superset<long,double> { typedef double type; };
philpem@5 2301 template<> struct superset<float,double> { typedef double type; };
philpem@5 2302
philpem@5 2303 template<typename t1, typename t2, typename t3> struct superset2 {
philpem@5 2304 typedef typename superset<t1, typename superset<t2,t3>::type>::type type;
philpem@5 2305 };
philpem@5 2306
philpem@5 2307 template<typename t1, typename t2, typename t3, typename t4> struct superset3 {
philpem@5 2308 typedef typename superset<t1, typename superset2<t2,t3,t4>::type>::type type;
philpem@5 2309 };
philpem@5 2310
philpem@5 2311 template<typename t1, typename t2> struct last { typedef t2 type; };
philpem@5 2312
philpem@5 2313 #define _cimg_Tuchar typename cimg::superset<T,unsigned char>::type
philpem@5 2314 #define _cimg_Tint typename cimg::superset<T,int>::type
philpem@5 2315 #define _cimg_Tfloat typename cimg::superset<T,float>::type
philpem@5 2316 #define _cimg_Tdouble typename cimg::superset<T,double>::type
philpem@5 2317 #define _cimg_Tt typename cimg::superset<T,t>::type
philpem@5 2318
philpem@5 2319 // Define internal library variables.
philpem@5 2320 //
philpem@5 2321 #if cimg_display==1
philpem@5 2322 struct X11info {
philpem@5 2323 volatile unsigned int nb_wins;
philpem@5 2324 pthread_t* event_thread;
philpem@5 2325 CImgDisplay* wins[1024];
philpem@5 2326 Display* display;
philpem@5 2327 unsigned int nb_bits;
philpem@5 2328 GC* gc;
philpem@5 2329 bool blue_first;
philpem@5 2330 bool byte_order;
philpem@5 2331 bool shm_enabled;
philpem@5 2332 #ifdef cimg_use_xrandr
philpem@5 2333 XRRScreenSize *resolutions;
philpem@5 2334 Rotation curr_rotation;
philpem@5 2335 unsigned int curr_resolution;
philpem@5 2336 unsigned int nb_resolutions;
philpem@5 2337 #endif
philpem@5 2338 X11info():nb_wins(0),event_thread(0),display(0),
philpem@5 2339 nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) {
philpem@5 2340 #ifdef cimg_use_xrandr
philpem@5 2341 resolutions = 0;
philpem@5 2342 curr_rotation = 0;
philpem@5 2343 curr_resolution = nb_resolutions = 0;
philpem@5 2344 #endif
philpem@5 2345 }
philpem@5 2346 };
philpem@5 2347 #if defined(cimg_module)
philpem@5 2348 X11info& X11attr();
philpem@5 2349 #elif defined(cimg_main)
philpem@5 2350 X11info& X11attr() { static X11info val; return val; }
philpem@5 2351 #else
philpem@5 2352 inline X11info& X11attr() { static X11info val; return val; }
philpem@5 2353 #endif
philpem@5 2354
philpem@5 2355 #elif cimg_display==2
philpem@5 2356 struct Win32info {
philpem@5 2357 HANDLE wait_event;
philpem@5 2358 Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); }
philpem@5 2359 };
philpem@5 2360 #if defined(cimg_module)
philpem@5 2361 Win32info& Win32attr();
philpem@5 2362 #elif defined(cimg_main)
philpem@5 2363 Win32info& Win32attr() { static Win32info val; return val; }
philpem@5 2364 #else
philpem@5 2365 inline Win32info& Win32attr() { static Win32info val; return val; }
philpem@5 2366 #endif
philpem@5 2367
philpem@5 2368 #elif cimg_display==3
philpem@5 2369 struct CarbonInfo {
philpem@5 2370 MPCriticalRegionID windowListCR; // Protects access to the list of windows
philpem@5 2371 int windowCount; // Count of displays used on the screen
philpem@5 2372 pthread_t event_thread; // The background event thread
philpem@5 2373 MPSemaphoreID sync_event; // Event used to perform tasks synchronizations
philpem@5 2374 MPSemaphoreID wait_event; // Event used to notify that new events occured on the display
philpem@5 2375 MPQueueID com_queue; // The message queue
philpem@5 2376 CarbonInfo(): windowCount(0),event_thread(0),sync_event(0),com_queue(0) {
philpem@5 2377 if (MPCreateCriticalRegion(&windowListCR) != noErr) // Create the critical region
philpem@5 2378 throw CImgDisplayException("MPCreateCriticalRegion failed.");
philpem@5 2379 if (MPCreateSemaphore(1, 0, &sync_event) != noErr) // Create the inter-thread sync object
philpem@5 2380 throw CImgDisplayException("MPCreateSemaphore failed.");
philpem@5 2381 if (MPCreateSemaphore(1, 0, &wait_event) != noErr) // Create the event sync object
philpem@5 2382 throw CImgDisplayException("MPCreateSemaphore failed.");
philpem@5 2383 if (MPCreateQueue(&com_queue) != noErr) // Create the shared queue
philpem@5 2384 throw CImgDisplayException("MPCreateQueue failed.");
philpem@5 2385 }
philpem@5 2386 ~CarbonInfo() {
philpem@5 2387 if (event_thread != 0) { // Terminates the resident thread, if needed
philpem@5 2388 pthread_cancel(event_thread);
philpem@5 2389 pthread_join(event_thread, NULL);
philpem@5 2390 event_thread = 0;
philpem@5 2391 }
philpem@5 2392 if (MPDeleteCriticalRegion(windowListCR) != noErr) // Delete the critical region
philpem@5 2393 throw CImgDisplayException("MPDeleteCriticalRegion failed.");
philpem@5 2394 if (MPDeleteSemaphore(wait_event) != noErr) // Delete the event sync event
philpem@5 2395 throw CImgDisplayException("MPDeleteEvent failed.");
philpem@5 2396 if (MPDeleteSemaphore(sync_event) != noErr) // Delete the inter-thread sync event
philpem@5 2397 throw CImgDisplayException("MPDeleteEvent failed.");
philpem@5 2398 if (MPDeleteQueue(com_queue) != noErr) // Delete the shared queue
philpem@5 2399 throw CImgDisplayException("MPDeleteQueue failed.");
philpem@5 2400 }
philpem@5 2401 };
philpem@5 2402 #if defined(cimg_module)
philpem@5 2403 CarbonInfo& CarbonAttr();
philpem@5 2404 #elif defined(cimg_main)
philpem@5 2405 CarbonInfo CarbonAttr() { static CarbonInfo val; return val; }
philpem@5 2406 #else
philpem@5 2407 inline CarbonInfo& CarbonAttr() { static CarbonInfo val; return val; }
philpem@5 2408 #endif
philpem@5 2409 #endif
philpem@5 2410
philpem@5 2411 #if cimg_display==1
philpem@5 2412 // Keycodes for X11-based graphical systems.
philpem@5 2413 //
philpem@5 2414 const unsigned int keyESC = XK_Escape;
philpem@5 2415 const unsigned int keyF1 = XK_F1;
philpem@5 2416 const unsigned int keyF2 = XK_F2;
philpem@5 2417 const unsigned int keyF3 = XK_F3;
philpem@5 2418 const unsigned int keyF4 = XK_F4;
philpem@5 2419 const unsigned int keyF5 = XK_F5;
philpem@5 2420 const unsigned int keyF6 = XK_F6;
philpem@5 2421 const unsigned int keyF7 = XK_F7;
philpem@5 2422 const unsigned int keyF8 = XK_F8;
philpem@5 2423 const unsigned int keyF9 = XK_F9;
philpem@5 2424 const unsigned int keyF10 = XK_F10;
philpem@5 2425 const unsigned int keyF11 = XK_F11;
philpem@5 2426 const unsigned int keyF12 = XK_F12;
philpem@5 2427 const unsigned int keyPAUSE = XK_Pause;
philpem@5 2428 const unsigned int key1 = XK_1;
philpem@5 2429 const unsigned int key2 = XK_2;
philpem@5 2430 const unsigned int key3 = XK_3;
philpem@5 2431 const unsigned int key4 = XK_4;
philpem@5 2432 const unsigned int key5 = XK_5;
philpem@5 2433 const unsigned int key6 = XK_6;
philpem@5 2434 const unsigned int key7 = XK_7;
philpem@5 2435 const unsigned int key8 = XK_8;
philpem@5 2436 const unsigned int key9 = XK_9;
philpem@5 2437 const unsigned int key0 = XK_0;
philpem@5 2438 const unsigned int keyBACKSPACE = XK_BackSpace;
philpem@5 2439 const unsigned int keyINSERT = XK_Insert;
philpem@5 2440 const unsigned int keyHOME = XK_Home;
philpem@5 2441 const unsigned int keyPAGEUP = XK_Page_Up;
philpem@5 2442 const unsigned int keyTAB = XK_Tab;
philpem@5 2443 const unsigned int keyQ = XK_q;
philpem@5 2444 const unsigned int keyW = XK_w;
philpem@5 2445 const unsigned int keyE = XK_e;
philpem@5 2446 const unsigned int keyR = XK_r;
philpem@5 2447 const unsigned int keyT = XK_t;
philpem@5 2448 const unsigned int keyY = XK_y;
philpem@5 2449 const unsigned int keyU = XK_u;
philpem@5 2450 const unsigned int keyI = XK_i;
philpem@5 2451 const unsigned int keyO = XK_o;
philpem@5 2452 const unsigned int keyP = XK_p;
philpem@5 2453 const unsigned int keyDELETE = XK_Delete;
philpem@5 2454 const unsigned int keyEND = XK_End;
philpem@5 2455 const unsigned int keyPAGEDOWN = XK_Page_Down;
philpem@5 2456 const unsigned int keyCAPSLOCK = XK_Caps_Lock;
philpem@5 2457 const unsigned int keyA = XK_a;
philpem@5 2458 const unsigned int keyS = XK_s;
philpem@5 2459 const unsigned int keyD = XK_d;
philpem@5 2460 const unsigned int keyF = XK_f;
philpem@5 2461 const unsigned int keyG = XK_g;
philpem@5 2462 const unsigned int keyH = XK_h;
philpem@5 2463 const unsigned int keyJ = XK_j;
philpem@5 2464 const unsigned int keyK = XK_k;
philpem@5 2465 const unsigned int keyL = XK_l;
philpem@5 2466 const unsigned int keyENTER = XK_Return;
philpem@5 2467 const unsigned int keySHIFTLEFT = XK_Shift_L;
philpem@5 2468 const unsigned int keyZ = XK_z;
philpem@5 2469 const unsigned int keyX = XK_x;
philpem@5 2470 const unsigned int keyC = XK_c;
philpem@5 2471 const unsigned int keyV = XK_v;
philpem@5 2472 const unsigned int keyB = XK_b;
philpem@5 2473 const unsigned int keyN = XK_n;
philpem@5 2474 const unsigned int keyM = XK_m;
philpem@5 2475 const unsigned int keySHIFTRIGHT = XK_Shift_R;
philpem@5 2476 const unsigned int keyARROWUP = XK_Up;
philpem@5 2477 const unsigned int keyCTRLLEFT = XK_Control_L;
philpem@5 2478 const unsigned int keyAPPLEFT = XK_Super_L;
philpem@5 2479 const unsigned int keyALT = XK_Alt_L;
philpem@5 2480 const unsigned int keySPACE = XK_space;
philpem@5 2481 const unsigned int keyALTGR = XK_Alt_R;
philpem@5 2482 const unsigned int keyAPPRIGHT = XK_Super_R;
philpem@5 2483 const unsigned int keyMENU = XK_Menu;
philpem@5 2484 const unsigned int keyCTRLRIGHT = XK_Control_R;
philpem@5 2485 const unsigned int keyARROWLEFT = XK_Left;
philpem@5 2486 const unsigned int keyARROWDOWN = XK_Down;
philpem@5 2487 const unsigned int keyARROWRIGHT = XK_Right;
philpem@5 2488 const unsigned int keyPAD0 = XK_KP_0;
philpem@5 2489 const unsigned int keyPAD1 = XK_KP_1;
philpem@5 2490 const unsigned int keyPAD2 = XK_KP_2;
philpem@5 2491 const unsigned int keyPAD3 = XK_KP_3;
philpem@5 2492 const unsigned int keyPAD4 = XK_KP_4;
philpem@5 2493 const unsigned int keyPAD5 = XK_KP_5;
philpem@5 2494 const unsigned int keyPAD6 = XK_KP_6;
philpem@5 2495 const unsigned int keyPAD7 = XK_KP_7;
philpem@5 2496 const unsigned int keyPAD8 = XK_KP_8;
philpem@5 2497 const unsigned int keyPAD9 = XK_KP_9;
philpem@5 2498 const unsigned int keyPADADD = XK_KP_Add;
philpem@5 2499 const unsigned int keyPADSUB = XK_KP_Subtract;
philpem@5 2500 const unsigned int keyPADMUL = XK_KP_Multiply;
philpem@5 2501 const unsigned int keyPADDIV = XK_KP_Divide;
philpem@5 2502
philpem@5 2503 #elif cimg_display==2
philpem@5 2504 // Keycodes for Windows.
philpem@5 2505 //
philpem@5 2506 const unsigned int keyESC = VK_ESCAPE;
philpem@5 2507 const unsigned int keyF1 = VK_F1;
philpem@5 2508 const unsigned int keyF2 = VK_F2;
philpem@5 2509 const unsigned int keyF3 = VK_F3;
philpem@5 2510 const unsigned int keyF4 = VK_F4;
philpem@5 2511 const unsigned int keyF5 = VK_F5;
philpem@5 2512 const unsigned int keyF6 = VK_F6;
philpem@5 2513 const unsigned int keyF7 = VK_F7;
philpem@5 2514 const unsigned int keyF8 = VK_F8;
philpem@5 2515 const unsigned int keyF9 = VK_F9;
philpem@5 2516 const unsigned int keyF10 = VK_F10;
philpem@5 2517 const unsigned int keyF11 = VK_F11;
philpem@5 2518 const unsigned int keyF12 = VK_F12;
philpem@5 2519 const unsigned int keyPAUSE = VK_PAUSE;
philpem@5 2520 const unsigned int key1 = '1';
philpem@5 2521 const unsigned int key2 = '2';
philpem@5 2522 const unsigned int key3 = '3';
philpem@5 2523 const unsigned int key4 = '4';
philpem@5 2524 const unsigned int key5 = '5';
philpem@5 2525 const unsigned int key6 = '6';
philpem@5 2526 const unsigned int key7 = '7';
philpem@5 2527 const unsigned int key8 = '8';
philpem@5 2528 const unsigned int key9 = '9';
philpem@5 2529 const unsigned int key0 = '0';
philpem@5 2530 const unsigned int keyBACKSPACE = VK_BACK;
philpem@5 2531 const unsigned int keyINSERT = VK_INSERT;
philpem@5 2532 const unsigned int keyHOME = VK_HOME;
philpem@5 2533 const unsigned int keyPAGEUP = VK_PRIOR;
philpem@5 2534 const unsigned int keyTAB = VK_TAB;
philpem@5 2535 const unsigned int keyQ = 'Q';
philpem@5 2536 const unsigned int keyW = 'W';
philpem@5 2537 const unsigned int keyE = 'E';
philpem@5 2538 const unsigned int keyR = 'R';
philpem@5 2539 const unsigned int keyT = 'T';
philpem@5 2540 const unsigned int keyY = 'Y';
philpem@5 2541 const unsigned int keyU = 'U';
philpem@5 2542 const unsigned int keyI = 'I';
philpem@5 2543 const unsigned int keyO = 'O';
philpem@5 2544 const unsigned int keyP = 'P';
philpem@5 2545 const unsigned int keyDELETE = VK_DELETE;
philpem@5 2546 const unsigned int keyEND = VK_END;
philpem@5 2547 const unsigned int keyPAGEDOWN = VK_NEXT;
philpem@5 2548 const unsigned int keyCAPSLOCK = VK_CAPITAL;
philpem@5 2549 const unsigned int keyA = 'A';
philpem@5 2550 const unsigned int keyS = 'S';
philpem@5 2551 const unsigned int keyD = 'D';
philpem@5 2552 const unsigned int keyF = 'F';
philpem@5 2553 const unsigned int keyG = 'G';
philpem@5 2554 const unsigned int keyH = 'H';
philpem@5 2555 const unsigned int keyJ = 'J';
philpem@5 2556 const unsigned int keyK = 'K';
philpem@5 2557 const unsigned int keyL = 'L';
philpem@5 2558 const unsigned int keyENTER = VK_RETURN;
philpem@5 2559 const unsigned int keySHIFTLEFT = VK_SHIFT;
philpem@5 2560 const unsigned int keyZ = 'Z';
philpem@5 2561 const unsigned int keyX = 'X';
philpem@5 2562 const unsigned int keyC = 'C';
philpem@5 2563 const unsigned int keyV = 'V';
philpem@5 2564 const unsigned int keyB = 'B';
philpem@5 2565 const unsigned int keyN = 'N';
philpem@5 2566 const unsigned int keyM = 'M';
philpem@5 2567 const unsigned int keySHIFTRIGHT = VK_SHIFT;
philpem@5 2568 const unsigned int keyARROWUP = VK_UP;
philpem@5 2569 const unsigned int keyCTRLLEFT = VK_CONTROL;
philpem@5 2570 const unsigned int keyAPPLEFT = VK_LWIN;
philpem@5 2571 const unsigned int keyALT = VK_LMENU;
philpem@5 2572 const unsigned int keySPACE = VK_SPACE;
philpem@5 2573 const unsigned int keyALTGR = VK_CONTROL;
philpem@5 2574 const unsigned int keyAPPRIGHT = VK_RWIN;
philpem@5 2575 const unsigned int keyMENU = VK_APPS;
philpem@5 2576 const unsigned int keyCTRLRIGHT = VK_CONTROL;
philpem@5 2577 const unsigned int keyARROWLEFT = VK_LEFT;
philpem@5 2578 const unsigned int keyARROWDOWN = VK_DOWN;
philpem@5 2579 const unsigned int keyARROWRIGHT = VK_RIGHT;
philpem@5 2580 const unsigned int keyPAD0 = 0x60;
philpem@5 2581 const unsigned int keyPAD1 = 0x61;
philpem@5 2582 const unsigned int keyPAD2 = 0x62;
philpem@5 2583 const unsigned int keyPAD3 = 0x63;
philpem@5 2584 const unsigned int keyPAD4 = 0x64;
philpem@5 2585 const unsigned int keyPAD5 = 0x65;
philpem@5 2586 const unsigned int keyPAD6 = 0x66;
philpem@5 2587 const unsigned int keyPAD7 = 0x67;
philpem@5 2588 const unsigned int keyPAD8 = 0x68;
philpem@5 2589 const unsigned int keyPAD9 = 0x69;
philpem@5 2590 const unsigned int keyPADADD = VK_ADD;
philpem@5 2591 const unsigned int keyPADSUB = VK_SUBTRACT;
philpem@5 2592 const unsigned int keyPADMUL = VK_MULTIPLY;
philpem@5 2593 const unsigned int keyPADDIV = VK_DIVIDE;
philpem@5 2594
philpem@5 2595 #elif cimg_display==3
philpem@5 2596 // Keycodes for MacOSX, when using the Carbon framework.
philpem@5 2597 //
philpem@5 2598 const unsigned int keyESC = kEscapeCharCode;
philpem@5 2599 const unsigned int keyF1 = 2U;
philpem@5 2600 const unsigned int keyF2 = 3U;
philpem@5 2601 const unsigned int keyF3 = 4U;
philpem@5 2602 const unsigned int keyF4 = 5U;
philpem@5 2603 const unsigned int keyF5 = 6U;
philpem@5 2604 const unsigned int keyF6 = 7U;
philpem@5 2605 const unsigned int keyF7 = 8U;
philpem@5 2606 const unsigned int keyF8 = 9U;
philpem@5 2607 const unsigned int keyF9 = 10U;
philpem@5 2608 const unsigned int keyF10 = 11U;
philpem@5 2609 const unsigned int keyF11 = 12U;
philpem@5 2610 const unsigned int keyF12 = 13U;
philpem@5 2611 const unsigned int keyPAUSE = 14U;
philpem@5 2612 const unsigned int key1 = '1';
philpem@5 2613 const unsigned int key2 = '2';
philpem@5 2614 const unsigned int key3 = '3';
philpem@5 2615 const unsigned int key4 = '4';
philpem@5 2616 const unsigned int key5 = '5';
philpem@5 2617 const unsigned int key6 = '6';
philpem@5 2618 const unsigned int key7 = '7';
philpem@5 2619 const unsigned int key8 = '8';
philpem@5 2620 const unsigned int key9 = '9';
philpem@5 2621 const unsigned int key0 = '0';
philpem@5 2622 const unsigned int keyBACKSPACE = kBackspaceCharCode;
philpem@5 2623 const unsigned int keyINSERT = 26U;
philpem@5 2624 const unsigned int keyHOME = kHomeCharCode;
philpem@5 2625 const unsigned int keyPAGEUP = kPageUpCharCode;
philpem@5 2626 const unsigned int keyTAB = kTabCharCode;
philpem@5 2627 const unsigned int keyQ = 'q';
philpem@5 2628 const unsigned int keyW = 'w';
philpem@5 2629 const unsigned int keyE = 'e';
philpem@5 2630 const unsigned int keyR = 'r';
philpem@5 2631 const unsigned int keyT = 't';
philpem@5 2632 const unsigned int keyY = 'y';
philpem@5 2633 const unsigned int keyU = 'u';
philpem@5 2634 const unsigned int keyI = 'i';
philpem@5 2635 const unsigned int keyO = 'o';
philpem@5 2636 const unsigned int keyP = 'p';
philpem@5 2637 const unsigned int keyDELETE = kDeleteCharCode;
philpem@5 2638 const unsigned int keyEND = kEndCharCode;
philpem@5 2639 const unsigned int keyPAGEDOWN = kPageDownCharCode;
philpem@5 2640 const unsigned int keyCAPSLOCK = 43U;
philpem@5 2641 const unsigned int keyA = 'a';
philpem@5 2642 const unsigned int keyS = 's';
philpem@5 2643 const unsigned int keyD = 'd';
philpem@5 2644 const unsigned int keyF = 'f';
philpem@5 2645 const unsigned int keyG = 'g';
philpem@5 2646 const unsigned int keyH = 'h';
philpem@5 2647 const unsigned int keyJ = 'j';
philpem@5 2648 const unsigned int keyK = 'k';
philpem@5 2649 const unsigned int keyL = 'l';
philpem@5 2650 const unsigned int keyENTER = kEnterCharCode;
philpem@5 2651 const unsigned int keySHIFTLEFT = 54U; //Macintosh modifier key, emulated
philpem@5 2652 const unsigned int keyZ = 'z';
philpem@5 2653 const unsigned int keyX = 'x';
philpem@5 2654 const unsigned int keyC = 'c';
philpem@5 2655 const unsigned int keyV = 'v';
philpem@5 2656 const unsigned int keyB = 'b';
philpem@5 2657 const unsigned int keyN = 'n';
philpem@5 2658 const unsigned int keyM = 'm';
philpem@5 2659 const unsigned int keySHIFTRIGHT = 62U; //Macintosh modifier key, emulated
philpem@5 2660 const unsigned int keyARROWUP = kUpArrowCharCode;
philpem@5 2661 const unsigned int keyCTRLLEFT = 64U; //Macintosh modifier key, emulated
philpem@5 2662 const unsigned int keyAPPLEFT = 65U; //Macintosh modifier key, emulated
philpem@5 2663 const unsigned int keyALT = 66U;
philpem@5 2664 const unsigned int keySPACE = kSpaceCharCode;
philpem@5 2665 const unsigned int keyALTGR = 67U; //Macintosh modifier key, emulated
philpem@5 2666 const unsigned int keyAPPRIGHT = 68U; //Aliased on keyAPPLEFT
philpem@5 2667 const unsigned int keyMENU = 69U;
philpem@5 2668 const unsigned int keyCTRLRIGHT = 70U; //Macintosh modifier key, emulated
philpem@5 2669 const unsigned int keyARROWLEFT = kLeftArrowCharCode;
philpem@5 2670 const unsigned int keyARROWDOWN = kDownArrowCharCode;
philpem@5 2671 const unsigned int keyARROWRIGHT = kRightArrowCharCode;
philpem@5 2672 const unsigned int keyPAD0 = 74U;
philpem@5 2673 const unsigned int keyPAD1 = 75U;
philpem@5 2674 const unsigned int keyPAD2 = 76U;
philpem@5 2675 const unsigned int keyPAD3 = 77U;
philpem@5 2676 const unsigned int keyPAD4 = 78U;
philpem@5 2677 const unsigned int keyPAD5 = 79U;
philpem@5 2678 const unsigned int keyPAD6 = 80U;
philpem@5 2679 const unsigned int keyPAD7 = 81U;
philpem@5 2680 const unsigned int keyPAD8 = 82U;
philpem@5 2681 const unsigned int keyPAD9 = 83U;
philpem@5 2682 const unsigned int keyPADADD = 84U;
philpem@5 2683 const unsigned int keyPADSUB = 85U;
philpem@5 2684 const unsigned int keyPADMUL = 86U;
philpem@5 2685 const unsigned int keyPADDIV = 87U;
philpem@5 2686
philpem@5 2687 #else
philpem@5 2688 // Define unknow keycodes when no display are available.
philpem@5 2689 // (should rarely be used then !).
philpem@5 2690 //
philpem@5 2691 const unsigned int keyESC = 1U;
philpem@5 2692 const unsigned int keyF1 = 2U;
philpem@5 2693 const unsigned int keyF2 = 3U;
philpem@5 2694 const unsigned int keyF3 = 4U;
philpem@5 2695 const unsigned int keyF4 = 5U;
philpem@5 2696 const unsigned int keyF5 = 6U;
philpem@5 2697 const unsigned int keyF6 = 7U;
philpem@5 2698 const unsigned int keyF7 = 8U;
philpem@5 2699 const unsigned int keyF8 = 9U;
philpem@5 2700 const unsigned int keyF9 = 10U;
philpem@5 2701 const unsigned int keyF10 = 11U;
philpem@5 2702 const unsigned int keyF11 = 12U;
philpem@5 2703 const unsigned int keyF12 = 13U;
philpem@5 2704 const unsigned int keyPAUSE = 14U;
philpem@5 2705 const unsigned int key1 = 15U;
philpem@5 2706 const unsigned int key2 = 16U;
philpem@5 2707 const unsigned int key3 = 17U;
philpem@5 2708 const unsigned int key4 = 18U;
philpem@5 2709 const unsigned int key5 = 19U;
philpem@5 2710 const unsigned int key6 = 20U;
philpem@5 2711 const unsigned int key7 = 21U;
philpem@5 2712 const unsigned int key8 = 22U;
philpem@5 2713 const unsigned int key9 = 23U;
philpem@5 2714 const unsigned int key0 = 24U;
philpem@5 2715 const unsigned int keyBACKSPACE = 25U;
philpem@5 2716 const unsigned int keyINSERT = 26U;
philpem@5 2717 const unsigned int keyHOME = 27U;
philpem@5 2718 const unsigned int keyPAGEUP = 28U;
philpem@5 2719 const unsigned int keyTAB = 29U;
philpem@5 2720 const unsigned int keyQ = 30U;
philpem@5 2721 const unsigned int keyW = 31U;
philpem@5 2722 const unsigned int keyE = 32U;
philpem@5 2723 const unsigned int keyR = 33U;
philpem@5 2724 const unsigned int keyT = 34U;
philpem@5 2725 const unsigned int keyY = 35U;
philpem@5 2726 const unsigned int keyU = 36U;
philpem@5 2727 const unsigned int keyI = 37U;
philpem@5 2728 const unsigned int keyO = 38U;
philpem@5 2729 const unsigned int keyP = 39U;
philpem@5 2730 const unsigned int keyDELETE = 40U;
philpem@5 2731 const unsigned int keyEND = 41U;
philpem@5 2732 const unsigned int keyPAGEDOWN = 42U;
philpem@5 2733 const unsigned int keyCAPSLOCK = 43U;
philpem@5 2734 const unsigned int keyA = 44U;
philpem@5 2735 const unsigned int keyS = 45U;
philpem@5 2736 const unsigned int keyD = 46U;
philpem@5 2737 const unsigned int keyF = 47U;
philpem@5 2738 const unsigned int keyG = 48U;
philpem@5 2739 const unsigned int keyH = 49U;
philpem@5 2740 const unsigned int keyJ = 50U;
philpem@5 2741 const unsigned int keyK = 51U;
philpem@5 2742 const unsigned int keyL = 52U;
philpem@5 2743 const unsigned int keyENTER = 53U;
philpem@5 2744 const unsigned int keySHIFTLEFT = 54U;
philpem@5 2745 const unsigned int keyZ = 55U;
philpem@5 2746 const unsigned int keyX = 56U;
philpem@5 2747 const unsigned int keyC = 57U;
philpem@5 2748 const unsigned int keyV = 58U;
philpem@5 2749 const unsigned int keyB = 59U;
philpem@5 2750 const unsigned int keyN = 60U;
philpem@5 2751 const unsigned int keyM = 61U;
philpem@5 2752 const unsigned int keySHIFTRIGHT = 62U;
philpem@5 2753 const unsigned int keyARROWUP = 63U;
philpem@5 2754 const unsigned int keyCTRLLEFT = 64U;
philpem@5 2755 const unsigned int keyAPPLEFT = 65U;
philpem@5 2756 const unsigned int keyALT = 66U;
philpem@5 2757 const unsigned int keySPACE = 67U;
philpem@5 2758 const unsigned int keyALTGR = 68U;
philpem@5 2759 const unsigned int keyAPPRIGHT = 69U;
philpem@5 2760 const unsigned int keyMENU = 70U;
philpem@5 2761 const unsigned int keyCTRLRIGHT = 71U;
philpem@5 2762 const unsigned int keyARROWLEFT = 72U;
philpem@5 2763 const unsigned int keyARROWDOWN = 73U;
philpem@5 2764 const unsigned int keyARROWRIGHT = 74U;
philpem@5 2765 const unsigned int keyPAD0 = 75U;
philpem@5 2766 const unsigned int keyPAD1 = 76U;
philpem@5 2767 const unsigned int keyPAD2 = 77U;
philpem@5 2768 const unsigned int keyPAD3 = 78U;
philpem@5 2769 const unsigned int keyPAD4 = 79U;
philpem@5 2770 const unsigned int keyPAD5 = 80U;
philpem@5 2771 const unsigned int keyPAD6 = 81U;
philpem@5 2772 const unsigned int keyPAD7 = 82U;
philpem@5 2773 const unsigned int keyPAD8 = 83U;
philpem@5 2774 const unsigned int keyPAD9 = 84U;
philpem@5 2775 const unsigned int keyPADADD = 85U;
philpem@5 2776 const unsigned int keyPADSUB = 86U;
philpem@5 2777 const unsigned int keyPADMUL = 87U;
philpem@5 2778 const unsigned int keyPADDIV = 88U;
philpem@5 2779 #endif
philpem@5 2780
philpem@5 2781 const double valuePI = 3.14159265358979323846; //!< Definition of the mathematical constant PI
philpem@5 2782
philpem@5 2783 // Definition of a 7x11 font, used to return a default font for drawing text.
philpem@5 2784 const unsigned int font7x11[7*11*256/32] = {
philpem@5 2785 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2786 0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000,
philpem@5 2787 0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000,
philpem@5 2788 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2789 0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020,
philpem@5 2790 0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e,
philpem@5 2791 0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0,
philpem@5 2792 0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081,
philpem@5 2793 0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2794 0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111,
philpem@5 2795 0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2796 0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1,
philpem@5 2797 0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2798 0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111,
philpem@5 2799 0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2800 0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1,
philpem@5 2801 0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2802 0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111,
philpem@5 2803 0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2804 0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1,
philpem@5 2805 0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2806 0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a,
philpem@5 2807 0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2808 0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1,
philpem@5 2809 0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282,
philpem@5 2810 0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104,
philpem@5 2811 0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801,
philpem@5 2812 0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448,
philpem@5 2813 0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00,
philpem@5 2814 0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7,
philpem@5 2815 0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0,
philpem@5 2816 0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204,
philpem@5 2817 0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18,
philpem@5 2818 0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a,
philpem@5 2819 0x400000,0x44,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x62018,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31,0x80000800,
philpem@5 2820 0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2821 0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070
philpem@5 2822 };
philpem@5 2823
philpem@5 2824 // Definition of a 10x13 font (used in dialog boxes).
philpem@5 2825 const unsigned int font10x13[256*10*13/32] = {
philpem@5 2826 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2827 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80100c0,
philpem@5 2828 0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2829 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2830 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x4020120,
philpem@5 2831 0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2832 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x140,0x80000,0x200402,0x800000,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2833 0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2834 0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001,
philpem@5 2835 0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801,
philpem@5 2836 0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0,
philpem@5 2837 0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0,
philpem@5 2838 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010,
philpem@5 2839 0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480,
philpem@5 2840 0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,
philpem@5 2841 0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010,
philpem@5 2842 0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008,
philpem@5 2843 0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006,
philpem@5 2844 0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088,
philpem@5 2845 0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000,
philpem@5 2846 0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220,
philpem@5 2847 0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208,
philpem@5 2848 0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040,
philpem@5 2849 0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508,
philpem@5 2850 0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088,
philpem@5 2851 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018,
philpem@5 2852 0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220,
philpem@5 2853 0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2854 0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484,
philpem@5 2855 0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808,
philpem@5 2856 0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264,
philpem@5 2857 0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010,
philpem@5 2858 0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100,
philpem@5 2859 0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800,
philpem@5 2860 0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,
philpem@5 2861 0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822,
philpem@5 2862 0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200,
philpem@5 2863 0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000,
philpem@5 2864 0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2865 0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8,
philpem@5 2866 0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008,
philpem@5 2867 0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000,
philpem@5 2868 0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220,
philpem@5 2869 0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402,
philpem@5 2870 0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980,
philpem@5 2871 0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421,
philpem@5 2872 0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0,
philpem@5 2873 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020,
philpem@5 2874 0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701,
philpem@5 2875 0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,
philpem@5 2876 0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c,
philpem@5 2877 0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0,
philpem@5 2878 0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000,
philpem@5 2879 0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000,
philpem@5 2880 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0,
philpem@5 2881 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100000,0x0,0x0,0x0,0x0,0x2000,0x0,0x4020040,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,
philpem@5 2882 0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000,
philpem@5 2883 0x0,0x4,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x80f00000,0x0,0x0,0x0,0x800,0xa0001800,0x0,0x0,0x0,0x0,
philpem@5 2884 0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040
philpem@5 2885 };
philpem@5 2886
philpem@5 2887 // Definition of a 8x17 font.
philpem@5 2888 const unsigned int font8x17[8*17*256/32] = {
philpem@5 2889 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2890 0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008,
philpem@5 2891 0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0,
philpem@5 2892 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0,
philpem@5 2893 0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400,
philpem@5 2894 0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0,
philpem@5 2895 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4,
philpem@5 2896 0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0,
philpem@5 2897 0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812,
philpem@5 2898 0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181,
philpem@5 2899 0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00,
philpem@5 2900 0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808,
philpem@5 2901 0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810,
philpem@5 2902 0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000,
philpem@5 2903 0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040,
philpem@5 2904 0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040,
philpem@5 2905 0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141,
philpem@5 2906 0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101,
philpem@5 2907 0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c,
philpem@5 2908 0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024,
philpem@5 2909 0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840,
philpem@5 2910 0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c,
philpem@5 2911 0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04,
philpem@5 2912 0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066,
philpem@5 2913 0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000,
philpem@5 2914 0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040,
philpem@5 2915 0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600,
philpem@5 2916 0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000,
philpem@5 2917 0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850,
philpem@5 2918 0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008,
philpem@5 2919 0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f,
philpem@5 2920 0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242,
philpem@5 2921 0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710,
philpem@5 2922 0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242,
philpem@5 2923 0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020,
philpem@5 2924 0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118,
philpem@5 2925 0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0,
philpem@5 2926 0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444,
philpem@5 2927 0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010,
philpem@5 2928 0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200,
philpem@5 2929 0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042,
philpem@5 2930 0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,
philpem@5 2931 0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143,
philpem@5 2932 0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010,
philpem@5 2933 0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44,
philpem@5 2934 0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262,
philpem@5 2935 0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820,
philpem@5 2936 0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000,
philpem@5 2937 0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10,
philpem@5 2938 0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f,
philpem@5 2939 0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00,
philpem@5 2940 0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0,
philpem@5 2941 0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0,
philpem@5 2942 0x0,0x0,0x0,0x1000,0x1078,0x0,0x0,0x0,0x400500,0x0,0x1e081e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2943 0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0,
philpem@5 2944 0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0,
philpem@5 2945 0x0,0x0,0x400000,0x8000000,0x41e0400,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x104010,0x0,0x0,0x0,0x0,
philpem@5 2946 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x1c,0x7000,0x0,0x40020000,0x0,0x300000,
philpem@5 2947 0x0,0xe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x0,0x0,0x0,0x400000,0x38000000,0x0,0x0,0x1c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2948 0x1c,0x0,0x0,0x0,0x0,0x0,0x304030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2949 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2950 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2951 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2952 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 2953
philpem@5 2954 // Definition of a 10x19 font.
philpem@5 2955 const unsigned int font10x19[10*19*256/32] = {
philpem@5 2956 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2957 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3600000,0x36000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2958 0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0,
philpem@5 2959 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2960 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x1c000,0x0,0x0,0x0,0x0,0x6c,0x0,0x0,0x0,0x0,
philpem@5 2961 0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0,
philpem@5 2962 0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 2963 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x0,0x0,0x2200000,
philpem@5 2964 0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000,
philpem@5 2965 0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c,
philpem@5 2966 0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0,
philpem@5 2967 0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000,
philpem@5 2968 0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0,
philpem@5 2969 0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10,
philpem@5 2970 0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c,
philpem@5 2971 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000,
philpem@5 2972 0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000,
philpem@5 2973 0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000,
philpem@5 2974 0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301,
philpem@5 2975 0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c,
philpem@5 2976 0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202,
philpem@5 2977 0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409,
philpem@5 2978 0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000,
philpem@5 2979 0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020,
philpem@5 2980 0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190,
philpem@5 2981 0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202,
philpem@5 2982 0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902,
philpem@5 2983 0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024,
philpem@5 2984 0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888,
philpem@5 2985 0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482,
philpem@5 2986 0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838,
philpem@5 2987 0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41,
philpem@5 2988 0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902,
philpem@5 2989 0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108,
philpem@5 2990 0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850,
philpem@5 2991 0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482,
philpem@5 2992 0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408,
philpem@5 2993 0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182,
philpem@5 2994 0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040,
philpem@5 2995 0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022,
philpem@5 2996 0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048,
philpem@5 2997 0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120,
philpem@5 2998 0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090,
philpem@5 2999 0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
philpem@5 3000 0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040,
philpem@5 3001 0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101,
philpem@5 3002 0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048,
philpem@5 3003 0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210,
philpem@5 3004 0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090,
philpem@5 3005 0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,
philpem@5 3006 0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040,
philpem@5 3007 0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100,
philpem@5 3008 0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000,
philpem@5 3009 0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210,
philpem@5 3010 0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f,
philpem@5 3011 0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224,
philpem@5 3012 0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902,
philpem@5 3013 0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021,
philpem@5 3014 0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020,
philpem@5 3015 0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010,
philpem@5 3016 0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020,
philpem@5 3017 0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000,
philpem@5 3018 0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021,
philpem@5 3019 0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008,
philpem@5 3020 0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200,
philpem@5 3021 0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020,
philpem@5 3022 0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024,
philpem@5 3023 0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301,
philpem@5 3024 0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102,
philpem@5 3025 0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000,
philpem@5 3026 0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007,
philpem@5 3027 0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842,
philpem@5 3028 0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661,
philpem@5 3029 0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07,
philpem@5 3030 0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000,
philpem@5 3031 0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360,
philpem@5 3032 0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0,
philpem@5 3033 0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e,
philpem@5 3034 0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0,
philpem@5 3035 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0xc06,0xc,0x100,0x0,0x0,0x0,0x3000,0x0,0x20000000,0x0,0x0,0x0,0x0,0xc000,
philpem@5 3036 0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000,
philpem@5 3037 0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3038 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1040010,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000,0x60c,0x18,0x0,
philpem@5 3039 0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000,
philpem@5 3040 0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400,
philpem@5 3041 0x2,0x1e02000,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,0x0,0x2040020,0x0,0x0,0x0,0x0,
philpem@5 3042 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x4000,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3043 0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000,
philpem@5 3044 0x0,0x0,0x0,0x1000,0x1c00,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x380000,0x0,0x0,0x0,0x0,0x0,0x0,0xe0400e0,
philpem@5 3045 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc,
philpem@5 3046 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3047 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 3048
philpem@5 3049 // Definition of a 12x24 font.
philpem@5 3050 const unsigned int font12x24[12*24*256/32] = {
philpem@5 3051 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3052 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x19,0x80000000,0x198000,0x0,0x0,0x0,0x0,
philpem@5 3053 0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c,
philpem@5 3054 0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3055 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3056 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3057 0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003,
philpem@5 3058 0xf01980,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3059 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3060 0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x60000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7007,0x3c0000,0x3006019,
philpem@5 3061 0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0,
philpem@5 3062 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3063 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000000,
philpem@5 3064 0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000,
philpem@5 3065 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000,
philpem@5 3066 0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6,
philpem@5 3067 0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f,
philpem@5 3068 0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603,
philpem@5 3069 0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8,
philpem@5 3070 0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3,
philpem@5 3071 0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00,
philpem@5 3072 0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,
philpem@5 3073 0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc,
philpem@5 3074 0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003,
philpem@5 3075 0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f,
philpem@5 3076 0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006,
philpem@5 3077 0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009,
philpem@5 3078 0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0,
philpem@5 3079 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018,
philpem@5 3080 0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00,
philpem@5 3081 0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000,
philpem@5 3082 0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000,
philpem@5 3083 0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3,
philpem@5 3084 0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980,
philpem@5 3085 0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000,
philpem@5 3086 0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60,
philpem@5 3087 0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,
philpem@5 3088 0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f,
philpem@5 3089 0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600,
philpem@5 3090 0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,
philpem@5 3091 0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000,
philpem@5 3092 0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606,
philpem@5 3093 0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6,
philpem@5 3094 0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f,
philpem@5 3095 0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001,
philpem@5 3096 0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061,
philpem@5 3097 0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6,
philpem@5 3098 0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000,
philpem@5 3099 0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660,
philpem@5 3100 0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d,
philpem@5 3101 0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180,
philpem@5 3102 0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020,
philpem@5 3103 0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660,
philpem@5 3104 0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060,
philpem@5 3105 0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000,
philpem@5 3106 0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006,
philpem@5 3107 0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06,
philpem@5 3108 0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090,
philpem@5 3109 0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006,
philpem@5 3110 0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066,
philpem@5 3111 0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183,
philpem@5 3112 0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044,
philpem@5 3113 0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001,
philpem@5 3114 0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003,
philpem@5 3115 0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1,
philpem@5 3116 0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f,
philpem@5 3117 0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660,
philpem@5 3118 0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60,
philpem@5 3119 0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000,
philpem@5 3120 0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001,
philpem@5 3121 0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003,
philpem@5 3122 0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603,
philpem@5 3123 0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00,
philpem@5 3124 0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066,
philpem@5 3125 0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
philpem@5 3126 0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004,
philpem@5 3127 0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006,
philpem@5 3128 0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06,
philpem@5 3129 0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de,
philpem@5 3130 0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6,
philpem@5 3131 0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,
philpem@5 3132 0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6,
philpem@5 3133 0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000,
philpem@5 3134 0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006,
philpem@5 3135 0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06,
philpem@5 3136 0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc,
philpem@5 3137 0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000,
philpem@5 3138 0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8,
philpem@5 3139 0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,
philpem@5 3140 0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000,
philpem@5 3141 0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e,
philpem@5 3142 0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c,
philpem@5 3143 0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000,
philpem@5 3144 0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140,
philpem@5 3145 0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060,
philpem@5 3146 0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0,
philpem@5 3147 0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030,
philpem@5 3148 0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60,
philpem@5 3149 0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c,
philpem@5 3150 0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000,
philpem@5 3151 0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240,
philpem@5 3152 0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0,
philpem@5 3153 0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71,
philpem@5 3154 0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300,
philpem@5 3155 0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8,
philpem@5 3156 0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8,
philpem@5 3157 0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0,
philpem@5 3158 0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000,
philpem@5 3159 0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000,
philpem@5 3160 0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83,
philpem@5 3161 0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000,
philpem@5 3162 0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6,
philpem@5 3163 0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6,
philpem@5 3164 0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0,
philpem@5 3165 0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0,
philpem@5 3166 0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f,
philpem@5 3167 0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c,
philpem@5 3168 0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0,
philpem@5 3169 0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0,
philpem@5 3170 0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6,
philpem@5 3171 0x12000,0x2000000,0x40,0x20004000,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3172 0x0,0xc06000c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x2004000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,
philpem@5 3173 0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000,
philpem@5 3174 0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000,
philpem@5 3175 0x40,0x7e004000,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc06000c0,0x0,
philpem@5 3176 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x300c000,0xc00,0x0,0x0,0x0,0x0,0x0,0xc00000,0x0,0x7800000,0x0,
philpem@5 3177 0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000,
philpem@5 3178 0x10,0xfc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x60000,0x0,0x0,0x0,0x0,0x6,0x0,0x1000000,0x0,0x0,0x0,0x0,
philpem@5 3179 0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3180 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,
philpem@5 3181 0x0,0x1f0,0x3c,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x600,0x0,0x0,0xf000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3182 0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xe000000,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x0,0x0,0x0,0x0,
philpem@5 3183 0x0,0x0,0x0,0x3,0x80600380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3184 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3185 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3186 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 3187
philpem@5 3188 // Definition of a 16x32 font.
philpem@5 3189 const unsigned int font16x32[16*32*256/32] = {
philpem@5 3190 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3191 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3192 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3193 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730,
philpem@5 3194 0xe700000,0x700,0xe003c0,0xe7000e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3195 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3196 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3197 0x0,0x0,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3198 0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180,
philpem@5 3199 0x1c00660,0xe7001c0,0x0,0x0,0x0,0x380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3200 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3201 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
philpem@5 3202 0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00380,
philpem@5 3203 0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380,
philpem@5 3204 0x0,0x0,0x0,0x7c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3205 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3206 0x0,0x0,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,
philpem@5 3207 0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000,
philpem@5 3208 0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070,
philpem@5 3209 0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3210 0x0,0x0,0x0,0x800000,0x0,0x600600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3211 0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,
philpem@5 3212 0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000,
philpem@5 3213 0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0xc000c00,0x43800000,0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3214 0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700,
philpem@5 3215 0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180,
philpem@5 3216 0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0,
philpem@5 3217 0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000,
philpem@5 3218 0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000,
philpem@5 3219 0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f,
philpem@5 3220 0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0,
philpem@5 3221 0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038,
philpem@5 3222 0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0,
philpem@5 3223 0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,
philpem@5 3224 0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0,
philpem@5 3225 0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007,
philpem@5 3226 0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0,
philpem@5 3227 0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0,
philpem@5 3228 0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000,
philpem@5 3229 0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,
philpem@5 3230 0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0,
philpem@5 3231 0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0,
philpem@5 3232 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0,
philpem@5 3233 0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0,
philpem@5 3234 0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000,
philpem@5 3235 0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0,
philpem@5 3236 0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e,
philpem@5 3237 0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0,
philpem@5 3238 0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038,
philpem@5 3239 0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0,
philpem@5 3240 0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300,
philpem@5 3241 0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08,
philpem@5 3242 0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380,
philpem@5 3243 0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,
philpem@5 3244 0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c,
philpem@5 3245 0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00,
philpem@5 3246 0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,
philpem@5 3247 0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3248 0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0,
philpem@5 3249 0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000,
philpem@5 3250 0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0,
philpem@5 3251 0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,
philpem@5 3252 0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0,
philpem@5 3253 0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000,
philpem@5 3254 0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000,
philpem@5 3255 0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000,
philpem@5 3256 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180,
philpem@5 3257 0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000,
philpem@5 3258 0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000,
philpem@5 3259 0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007,
philpem@5 3260 0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70,
philpem@5 3261 0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180,
philpem@5 3262 0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000,
philpem@5 3263 0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0,
philpem@5 3264 0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838,
philpem@5 3265 0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180,
philpem@5 3266 0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770,
philpem@5 3267 0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770,
philpem@5 3268 0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc,
philpem@5 3269 0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380,
philpem@5 3270 0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12,
philpem@5 3271 0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770,
philpem@5 3272 0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038,
philpem@5 3273 0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0,
philpem@5 3274 0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3275 0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380,
philpem@5 3276 0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00,
philpem@5 3277 0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c,
philpem@5 3278 0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400,
philpem@5 3279 0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe,
philpem@5 3280 0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770,
philpem@5 3281 0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038,
philpem@5 3282 0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78,
philpem@5 3283 0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3284 0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0,
philpem@5 3285 0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c,
philpem@5 3286 0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0,
philpem@5 3287 0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8,
philpem@5 3288 0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0,
philpem@5 3289 0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0,
philpem@5 3290 0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c,
philpem@5 3291 0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c,
philpem@5 3292 0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0,
philpem@5 3293 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0,
philpem@5 3294 0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0,
philpem@5 3295 0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800,
philpem@5 3296 0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380,
philpem@5 3297 0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0,
philpem@5 3298 0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860,
philpem@5 3299 0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,
philpem@5 3300 0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c,
philpem@5 3301 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70,
philpem@5 3302 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe,
philpem@5 3303 0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc,
philpem@5 3304 0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc,
philpem@5 3305 0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70,
philpem@5 3306 0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180,
philpem@5 3307 0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0,
philpem@5 3308 0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0,
philpem@5 3309 0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc,
philpem@5 3310 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70,
philpem@5 3311 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe,
philpem@5 3312 0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000,
philpem@5 3313 0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0,
philpem@5 3314 0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc,
philpem@5 3315 0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0,
philpem@5 3316 0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000,
philpem@5 3317 0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000,
philpem@5 3318 0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc,
philpem@5 3319 0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838,
philpem@5 3320 0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0,
philpem@5 3321 0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000,
philpem@5 3322 0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0,
philpem@5 3323 0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc,
philpem@5 3324 0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0,
philpem@5 3325 0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838,
philpem@5 3326 0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
philpem@5 3327 0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c,
philpem@5 3328 0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0,
philpem@5 3329 0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180,
philpem@5 3330 0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000,
philpem@5 3331 0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0,
philpem@5 3332 0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c,
philpem@5 3333 0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0,
philpem@5 3334 0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838,
philpem@5 3335 0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
philpem@5 3336 0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c,
philpem@5 3337 0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0,
philpem@5 3338 0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180,
philpem@5 3339 0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c,
philpem@5 3340 0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c,
philpem@5 3341 0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0,
philpem@5 3342 0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0,
philpem@5 3343 0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0,
philpem@5 3344 0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8,
philpem@5 3345 0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800,
philpem@5 3346 0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0,
philpem@5 3347 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000,
philpem@5 3348 0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000,
philpem@5 3349 0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0,
philpem@5 3350 0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78,
philpem@5 3351 0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000,
philpem@5 3352 0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838,
philpem@5 3353 0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0,
philpem@5 3354 0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c,
philpem@5 3355 0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0,
philpem@5 3356 0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180,
philpem@5 3357 0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18,
philpem@5 3358 0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380,
philpem@5 3359 0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78,
philpem@5 3360 0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0,
philpem@5 3361 0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000,
philpem@5 3362 0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000,
philpem@5 3363 0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c,
philpem@5 3364 0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78,
philpem@5 3365 0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000,
philpem@5 3366 0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8,
philpem@5 3367 0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380,
philpem@5 3368 0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8,
philpem@5 3369 0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380,
philpem@5 3370 0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe,
philpem@5 3371 0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,
philpem@5 3372 0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc,
philpem@5 3373 0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8,
philpem@5 3374 0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180,
philpem@5 3375 0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8,
philpem@5 3376 0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0,
philpem@5 3377 0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38,
philpem@5 3378 0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000,
philpem@5 3379 0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000,
philpem@5 3380 0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078,
philpem@5 3381 0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0,
philpem@5 3382 0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0,
philpem@5 3383 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x3000000,0x3800,0x0,0x0,0x0,0x0,
philpem@5 3384 0x0,0x300,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x0,0x0,0x0,0x380,0x3801c0,0x0,0x0,0x0,0x0,0x1c,0x0,0xe00000,
philpem@5 3385 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3386 0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0,
philpem@5 3387 0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,
philpem@5 3388 0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,0xc00300,0x0,0x7000000,
philpem@5 3389 0x7000,0x0,0x0,0x0,0x0,0x0,0x700,0x0,0x0,0xf040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x3f0,0x1c0fc0,0x0,0x0,
philpem@5 3390 0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0,
philpem@5 3391 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
philpem@5 3392 0x0,0x7f800e0,0x7f80000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,
philpem@5 3393 0x0,0x0,0x0,0x0,0x0,0x0,0x700,0x38000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,
philpem@5 3394 0x0,0x600600,0x0,0x6000000,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,
philpem@5 3395 0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000,
philpem@5 3396 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000,
philpem@5 3397 0x0,0x3001c0,0x300000,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x0,0x0,
philpem@5 3398 0x0,0x0,0x0,0x0,0x0,0xf00,0x38000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x800000,0x0,
philpem@5 3399 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3400 0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3401 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000,
philpem@5 3402 0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3403 0x3e00,0x38003e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3404 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x7e0,0x0,0x1f000000,
philpem@5 3405 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3c00,0x0,0x1800000,0x0,0x0,0x7800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3406 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3407 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00,0x38003c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3408 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3409 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0,
philpem@5 3410 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3411 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3412 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3413 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3414 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3415 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3416 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3417 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3418 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3419 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3420 0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 3421
philpem@5 3422 // Definition of a 19x38 font.
philpem@5 3423 const unsigned int font19x38[19*38*256/32] = {
philpem@5 3424 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3425 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3426 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c380000,0x0,0x1c380,0x0,0x0,0x0,0x0,0x0,
philpem@5 3427 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800007,0x3c003,0x86000000,
philpem@5 3428 0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0,
philpem@5 3429 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3430 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3431 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3432 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe700000,0x0,0xe700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3433 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000,
philpem@5 3434 0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0,
philpem@5 3435 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3436 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3437 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3438 0x0,0x0,0x0,0x7e00000,0x0,0x7e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3439 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000,
philpem@5 3440 0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0,
philpem@5 3441 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3442 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3443 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,
philpem@5 3444 0x0,0x3c00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3445 0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000,
philpem@5 3446 0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3447 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3448 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3449 0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60000000,0x0,0x0,
philpem@5 3450 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c38,0x0,0x1,0xc3800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x0,
philpem@5 3451 0x0,0x0,0x0,0x0,0x0,0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000003,0x80018000,0x0,0xc180000,
philpem@5 3452 0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3453 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3454 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3455 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78c00,0xc30,
philpem@5 3456 0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0,
philpem@5 3457 0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700,
philpem@5 3458 0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3459 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3460 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x3800000,0x700000,0x38,
philpem@5 3461 0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1,
philpem@5 3462 0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000,
philpem@5 3463 0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3464 0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e,
philpem@5 3465 0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3466 0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800,
philpem@5 3467 0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01,
philpem@5 3468 0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000,
philpem@5 3469 0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000,
philpem@5 3470 0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c,
philpem@5 3471 0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0,
philpem@5 3472 0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,
philpem@5 3473 0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000,
philpem@5 3474 0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007,
philpem@5 3475 0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61800600,0x7f8001ff,0x70000,
philpem@5 3476 0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e,
philpem@5 3477 0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007,
philpem@5 3478 0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,
philpem@5 3479 0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00,
philpem@5 3480 0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000,
philpem@5 3481 0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00,
philpem@5 3482 0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67,
philpem@5 3483 0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc,
philpem@5 3484 0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3485 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff,
philpem@5 3486 0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0,
philpem@5 3487 0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000,
philpem@5 3488 0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000,
philpem@5 3489 0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c,
philpem@5 3490 0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38,
philpem@5 3491 0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,
philpem@5 3492 0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0,
philpem@5 3493 0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0,
philpem@5 3494 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00,
philpem@5 3495 0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07,
philpem@5 3496 0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380,
philpem@5 3497 0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,
philpem@5 3498 0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3,
philpem@5 3499 0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0,
philpem@5 3500 0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001,
philpem@5 3501 0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0,
philpem@5 3502 0x0,0x0,0x0,0x0,0x0,0x0,0xff0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3503 0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380,
philpem@5 3504 0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e,
philpem@5 3505 0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000,
philpem@5 3506 0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0,
philpem@5 3507 0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078,
philpem@5 3508 0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60,
philpem@5 3509 0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078,
philpem@5 3510 0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878,
philpem@5 3511 0x0,0x0,0x0,0x7,0x80000080,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,
philpem@5 3512 0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707,
philpem@5 3513 0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01,
philpem@5 3514 0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff,
philpem@5 3515 0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc,
philpem@5 3516 0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000,
philpem@5 3517 0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606,
philpem@5 3518 0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c,
philpem@5 3519 0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07,
philpem@5 3520 0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007,
philpem@5 3521 0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3522 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07,
philpem@5 3523 0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700,
philpem@5 3524 0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038,
philpem@5 3525 0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe,
philpem@5 3526 0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000,
philpem@5 3527 0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0,
philpem@5 3528 0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000,
philpem@5 3529 0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001,
philpem@5 3530 0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff,
philpem@5 3531 0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8,
philpem@5 3532 0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3533 0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800,
philpem@5 3534 0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00,
philpem@5 3535 0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000,
philpem@5 3536 0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03,
philpem@5 3537 0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000,
philpem@5 3538 0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c,
philpem@5 3539 0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060,
philpem@5 3540 0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0,
philpem@5 3541 0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff,
philpem@5 3542 0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c,
philpem@5 3543 0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,
philpem@5 3544 0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07,
philpem@5 3545 0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1,
philpem@5 3546 0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8,
philpem@5 3547 0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03,
philpem@5 3548 0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0,
philpem@5 3549 0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c,
philpem@5 3550 0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3,
philpem@5 3551 0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,
philpem@5 3552 0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0,
philpem@5 3553 0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07,
philpem@5 3554 0xc1e0e03c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1,0x8701c600,0x1e0f01e0,0x1,
philpem@5 3555 0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81,
philpem@5 3556 0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0,
philpem@5 3557 0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e,
philpem@5 3558 0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e,
philpem@5 3559 0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000,
philpem@5 3560 0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0,
philpem@5 3561 0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f,
philpem@5 3562 0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e,
philpem@5 3563 0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800,
philpem@5 3564 0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0,
philpem@5 3565 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3,
philpem@5 3566 0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038,
philpem@5 3567 0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000,
philpem@5 3568 0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03,
philpem@5 3569 0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000,
philpem@5 3570 0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800,
philpem@5 3571 0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e,
philpem@5 3572 0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0,
philpem@5 3573 0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007,
philpem@5 3574 0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3,
philpem@5 3575 0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3576 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000,
philpem@5 3577 0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f,
philpem@5 3578 0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c,
philpem@5 3579 0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000,
philpem@5 3580 0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700,
philpem@5 3581 0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f,
philpem@5 3582 0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000,
philpem@5 3583 0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,
philpem@5 3584 0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000,
philpem@5 3585 0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007,
philpem@5 3586 0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3587 0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80,
philpem@5 3588 0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00,
philpem@5 3589 0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0,
philpem@5 3590 0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e,
philpem@5 3591 0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180,
philpem@5 3592 0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000,
philpem@5 3593 0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f,
philpem@5 3594 0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0,
philpem@5 3595 0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff,
philpem@5 3596 0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c,
philpem@5 3597 0xe0381c0,0x700e1c07,0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0xc000ff0,
philpem@5 3598 0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700,
philpem@5 3599 0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1,
philpem@5 3600 0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038,
philpem@5 3601 0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0,
philpem@5 3602 0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef,
philpem@5 3603 0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800,
philpem@5 3604 0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0,
philpem@5 3605 0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,
philpem@5 3606 0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0,
philpem@5 3607 0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07,
philpem@5 3608 0x703870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x7f,0xffc00678,0x707f9c1e,0x38000001,
philpem@5 3609 0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700,
philpem@5 3610 0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0,
philpem@5 3611 0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc,
philpem@5 3612 0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb,
philpem@5 3613 0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000,
philpem@5 3614 0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000,
philpem@5 3615 0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,
philpem@5 3616 0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c,
philpem@5 3617 0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,
philpem@5 3618 0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3619 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3,
philpem@5 3620 0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,
philpem@5 3621 0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0,
philpem@5 3622 0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e,
philpem@5 3623 0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001,
philpem@5 3624 0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18,
philpem@5 3625 0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f,
philpem@5 3626 0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d,
philpem@5 3627 0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00,
philpem@5 3628 0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,
philpem@5 3629 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0061c,0xc0dc07,0xf0000001,0xc0000700,
philpem@5 3630 0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e,
philpem@5 3631 0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00,
philpem@5 3632 0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1,
philpem@5 3633 0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000,
philpem@5 3634 0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c,
philpem@5 3635 0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001,
philpem@5 3636 0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,
philpem@5 3637 0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038,
philpem@5 3638 0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c,
philpem@5 3639 0xe0381c0,0x70077807,0x701de0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x1c00061c,
philpem@5 3640 0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87,
philpem@5 3641 0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0,
philpem@5 3642 0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c,
philpem@5 3643 0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000,
philpem@5 3644 0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c,
philpem@5 3645 0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0,
philpem@5 3646 0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00,
philpem@5 3647 0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700,
philpem@5 3648 0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f,
philpem@5 3649 0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3650 0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e,
philpem@5 3651 0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07,
philpem@5 3652 0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700,
philpem@5 3653 0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e,
philpem@5 3654 0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f,
philpem@5 3655 0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0,
philpem@5 3656 0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c,
philpem@5 3657 0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787,
philpem@5 3658 0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001,
philpem@5 3659 0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0,
philpem@5 3660 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00,
philpem@5 3661 0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700,
philpem@5 3662 0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e,
philpem@5 3663 0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703,
philpem@5 3664 0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077,
philpem@5 3665 0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003,
philpem@5 3666 0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0,
philpem@5 3667 0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800,
philpem@5 3668 0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e,
philpem@5 3669 0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007,
philpem@5 3670 0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3671 0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c,
philpem@5 3672 0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0,
philpem@5 3673 0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03,
philpem@5 3674 0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0,
philpem@5 3675 0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0,
philpem@5 3676 0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0,
philpem@5 3677 0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f,
philpem@5 3678 0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff,
philpem@5 3679 0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe,
philpem@5 3680 0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3681 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc,
philpem@5 3682 0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700,
philpem@5 3683 0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff,
philpem@5 3684 0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe,
philpem@5 3685 0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000,
philpem@5 3686 0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000,
philpem@5 3687 0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc,
philpem@5 3688 0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000,
philpem@5 3689 0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff,
philpem@5 3690 0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780,
philpem@5 3691 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x30007fc0,0x1e00f8,0x78000000,0x70001c00,
philpem@5 3692 0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000,
philpem@5 3693 0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0,
philpem@5 3694 0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0,
philpem@5 3695 0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010,
philpem@5 3696 0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f,
philpem@5 3697 0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00,
philpem@5 3698 0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0,
philpem@5 3699 0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00,
philpem@5 3700 0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007,
philpem@5 3701 0x1f000700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x70001c00,0x0,
philpem@5 3702 0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
philpem@5 3703 0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
philpem@5 3704 0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
philpem@5 3705 0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000,
philpem@5 3706 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400000,
philpem@5 3707 0x0,0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x30001800,
philpem@5 3708 0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000,
philpem@5 3709 0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000,
philpem@5 3710 0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
philpem@5 3711 0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000,
philpem@5 3712 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3713 0x0,0x1c007,0x700,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x38003800,
philpem@5 3714 0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000,
philpem@5 3715 0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000,
philpem@5 3716 0x78000e,0x3c000,0x0,0x0,0x180001,0xc0018300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,
philpem@5 3717 0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0,
philpem@5 3718 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3719 0x38007,0xe00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x18003000,
philpem@5 3720 0x0,0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,
philpem@5 3721 0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000,
philpem@5 3722 0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,
philpem@5 3723 0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,
philpem@5 3724 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x23000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78007,
philpem@5 3725 0x1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x1c007000,0x0,0x0,
philpem@5 3726 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe0000,
philpem@5 3727 0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0,
philpem@5 3728 0x0,0x10007f,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x38,0x0,0x0,0x0,0x0,
philpem@5 3729 0x0,0x0,0x0,0x0,0x3800,0x0,0x1f800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3730 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f8007,0xfe00,0x0,0x0,0x0,0x0,
philpem@5 3731 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3732 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x7fe000,0x0,
philpem@5 3733 0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3734 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1f000,0x0,0x0,0x0,0x0,0x0,
philpem@5 3735 0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3736 0x0,0x0,0x0,0x0,0x0,0x0,0x3f0007,0xfc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3737 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3738 0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0,
philpem@5 3739 0x0,0x0,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3740 0x0,0x0,0x3800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3741 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c0007,0xf000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3742 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3743 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3744 0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3745 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3746 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 3747
philpem@5 3748 // Definition of a 29x57 font.
philpem@5 3749 const unsigned int font29x57[29*57*256/32] = {
philpem@5 3750 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3751 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3752 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3753 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3754 0x0,0x781e00,0x0,0x0,0x7,0x81e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3755 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0000,0xf8000,0x7e00000,0x0,0x7,
philpem@5 3756 0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000,
philpem@5 3757 0x7c00003f,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3758 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3759 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3760 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3761 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3762 0x0,0x0,0x0,0x0,0x0,0x0,0x3c3c00,0x0,0x0,0x3,0xc3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,
philpem@5 3763 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e0000,
philpem@5 3764 0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000,
philpem@5 3765 0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3766 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3767 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3768 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3769 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3770 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e7800,0x0,0x0,
philpem@5 3771 0x1,0xe7800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3772 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f,
philpem@5 3773 0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00,
philpem@5 3774 0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3775 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3776 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3777 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3778 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3779 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef000,0x0,0x0,0x0,0xef000000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3780 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3781 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800,
philpem@5 3782 0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3,
philpem@5 3783 0xc0001f0f,0x800003c0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3784 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3785 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3786 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3787 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3788 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3789 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3790 0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e,
philpem@5 3791 0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0,
philpem@5 3792 0x0,0x0,0x0,0x0,0x1f,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3793 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3794 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3795 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3796 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3797 0x0,0x7e000,0x0,0x0,0x0,0x7e000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3798 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003,
philpem@5 3799 0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0,
philpem@5 3800 0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000,
philpem@5 3801 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3802 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3803 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3804 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3805 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3806 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3807 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ff800,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3808 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3809 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3810 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3811 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3812 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3813 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3814 0x0,0x0,0x78,0xf000000,0x0,0x0,0x780f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c0,
philpem@5 3815 0x0,0x0,0x0,0x0,0x0,0x0,0x3fc00,0x1fe000,0x3ffc00,0x0,0x0,0x0,0x0,0x0,0x70,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3816 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0,
philpem@5 3817 0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,0x0,0x3e,0x0,
philpem@5 3818 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3819 0x0,0x0,0x0,0x30000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3820 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80000,
philpem@5 3821 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3822 0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0,
philpem@5 3823 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x0,0x0,0x0,0x0,0x0,0x0,0x39c00,0x1ce000,0x303e00,
philpem@5 3824 0x0,0x0,0x0,0x0,0x0,0x78,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,
philpem@5 3825 0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000,
philpem@5 3826 0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3827 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0xff,0x0,
philpem@5 3828 0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0,
philpem@5 3829 0x0,0x7f800,0x0,0x0,0x0,0xff00000,0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf8000000,0xfe,0x0,0x7f80,0x0,0x0,0x0,0x0,0x0,
philpem@5 3830 0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,
philpem@5 3831 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x3fc00,0x0,0x0,0x1fc000,0x0,0x0,0x0,0x1fc0,
philpem@5 3832 0x0,0xff000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe1c0000,0x1c,0x1c000000,0x0,0x0,0x1c1c0,0x0,0x0,0x0,0x0,0x1fe0000,
philpem@5 3833 0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000,
philpem@5 3834 0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,
philpem@5 3835 0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800,
philpem@5 3836 0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3,
philpem@5 3837 0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3838 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0,
philpem@5 3839 0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000,
philpem@5 3840 0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80,
philpem@5 3841 0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0,
philpem@5 3842 0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000,
philpem@5 3843 0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000,
philpem@5 3844 0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000,
philpem@5 3845 0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f,
philpem@5 3846 0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,
philpem@5 3847 0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,
philpem@5 3848 0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00,
philpem@5 3849 0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e,
philpem@5 3850 0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000,
philpem@5 3851 0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3852 0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe,
philpem@5 3853 0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000,
philpem@5 3854 0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff,
philpem@5 3855 0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00,
philpem@5 3856 0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3857 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80,
philpem@5 3858 0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000,
philpem@5 3859 0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0,
philpem@5 3860 0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff,
philpem@5 3861 0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0,
philpem@5 3862 0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003,
philpem@5 3863 0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d,
philpem@5 3864 0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,0x3e1f00,0x0,0x0,
philpem@5 3865 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
philpem@5 3866 0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc,
philpem@5 3867 0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff,
philpem@5 3868 0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff,
philpem@5 3869 0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000,
philpem@5 3870 0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,
philpem@5 3871 0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f,
philpem@5 3872 0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000,
philpem@5 3873 0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0,
philpem@5 3874 0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff,
philpem@5 3875 0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8,
philpem@5 3876 0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003,
philpem@5 3877 0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380,
philpem@5 3878 0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,
philpem@5 3879 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000,
philpem@5 3880 0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80,
philpem@5 3881 0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff,
philpem@5 3882 0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c,
philpem@5 3883 0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000,
philpem@5 3884 0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80,
philpem@5 3885 0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3886 0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00,
philpem@5 3887 0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000,
philpem@5 3888 0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe,
philpem@5 3889 0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,
philpem@5 3890 0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f,
philpem@5 3891 0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700,
philpem@5 3892 0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,0x3e1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3893 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f,
philpem@5 3894 0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007,
philpem@5 3895 0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007,
philpem@5 3896 0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f,
philpem@5 3897 0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,
philpem@5 3898 0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000,
philpem@5 3899 0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000,
philpem@5 3900 0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000,
philpem@5 3901 0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000,
philpem@5 3902 0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
philpem@5 3903 0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007,
philpem@5 3904 0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003,
philpem@5 3905 0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000,
philpem@5 3906 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3907 0x780000,0x3c1e0000,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000,
philpem@5 3908 0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007,
philpem@5 3909 0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00,
philpem@5 3910 0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1,
philpem@5 3911 0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,
philpem@5 3912 0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0,
philpem@5 3913 0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c,
philpem@5 3914 0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000,
philpem@5 3915 0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000,
philpem@5 3916 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00,
philpem@5 3917 0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000,
philpem@5 3918 0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007,
philpem@5 3919 0x800003c0,0x78000000,0xf00,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3920 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80,
philpem@5 3921 0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,
philpem@5 3922 0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f,
philpem@5 3923 0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800,
philpem@5 3924 0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,
philpem@5 3925 0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000,
philpem@5 3926 0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000,
philpem@5 3927 0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,
philpem@5 3928 0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000,
philpem@5 3929 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00,
philpem@5 3930 0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3931 0x0,0x0,0x307,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3932 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803,
philpem@5 3933 0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f,
philpem@5 3934 0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,
philpem@5 3935 0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e,
philpem@5 3936 0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,
philpem@5 3937 0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,
philpem@5 3938 0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,
philpem@5 3939 0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078,
philpem@5 3940 0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007,
philpem@5 3941 0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780,
philpem@5 3942 0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0,
philpem@5 3943 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0x0,0x1e0000,
philpem@5 3944 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3945 0x780000,0x3c1e0000,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,
philpem@5 3946 0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003,
philpem@5 3947 0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800,
philpem@5 3948 0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001,
philpem@5 3949 0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc,
philpem@5 3950 0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000,
philpem@5 3951 0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03,
philpem@5 3952 0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0,
philpem@5 3953 0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000,
philpem@5 3954 0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
philpem@5 3955 0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc,
philpem@5 3956 0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0,
philpem@5 3957 0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0,
philpem@5 3958 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,
philpem@5 3959 0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780,
philpem@5 3960 0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0,
philpem@5 3961 0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000,
philpem@5 3962 0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f,
philpem@5 3963 0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff,
philpem@5 3964 0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000,
philpem@5 3965 0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0,
philpem@5 3966 0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c,
philpem@5 3967 0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,
philpem@5 3968 0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,
philpem@5 3969 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,
philpem@5 3970 0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f,
philpem@5 3971 0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f,
philpem@5 3972 0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c,
philpem@5 3973 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
philpem@5 3974 0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f,
philpem@5 3975 0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e,
philpem@5 3976 0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001,
philpem@5 3977 0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001,
philpem@5 3978 0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f,
philpem@5 3979 0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780,
philpem@5 3980 0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007,
philpem@5 3981 0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000,
philpem@5 3982 0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0,
philpem@5 3983 0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787,
philpem@5 3984 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f,
philpem@5 3985 0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001,
philpem@5 3986 0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f,
philpem@5 3987 0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,
philpem@5 3988 0xe01efff8,0x3c00078,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 3989 0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00,
philpem@5 3990 0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0,
philpem@5 3991 0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079,
philpem@5 3992 0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c,
philpem@5 3993 0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00,
philpem@5 3994 0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f,
philpem@5 3995 0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000,
philpem@5 3996 0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000,
philpem@5 3997 0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780,
philpem@5 3998 0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00,
philpem@5 3999 0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000,
philpem@5 4000 0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e,
philpem@5 4001 0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff,
philpem@5 4002 0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff,
philpem@5 4003 0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,0x3c00078,0x0,
philpem@5 4004 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,
philpem@5 4005 0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e,
philpem@5 4006 0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c,
philpem@5 4007 0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001,
philpem@5 4008 0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801,
philpem@5 4009 0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc,
philpem@5 4010 0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780,
philpem@5 4011 0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f,
philpem@5 4012 0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000,
philpem@5 4013 0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078,
philpem@5 4014 0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001,
philpem@5 4015 0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,
philpem@5 4016 0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8,
philpem@5 4017 0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0,
philpem@5 4018 0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007,
philpem@5 4019 0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4020 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00,
philpem@5 4021 0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0,
philpem@5 4022 0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,
philpem@5 4023 0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807,
philpem@5 4024 0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c,
philpem@5 4025 0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000,
philpem@5 4026 0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18,
philpem@5 4027 0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0,
philpem@5 4028 0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe,
philpem@5 4029 0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078,
philpem@5 4030 0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000,
philpem@5 4031 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
philpem@5 4032 0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008,
philpem@5 4033 0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0,
philpem@5 4034 0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003,
philpem@5 4035 0xc01fc03e,0x1e000f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4036 0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00,
philpem@5 4037 0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80,
philpem@5 4038 0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e,
philpem@5 4039 0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000,
philpem@5 4040 0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000,
philpem@5 4041 0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c,
philpem@5 4042 0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00,
philpem@5 4043 0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00,
philpem@5 4044 0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000,
philpem@5 4045 0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00,
philpem@5 4046 0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,
philpem@5 4047 0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00,
philpem@5 4048 0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c,
philpem@5 4049 0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,
philpem@5 4050 0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4051 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0,
philpem@5 4052 0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078,
philpem@5 4053 0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,
philpem@5 4054 0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0,
philpem@5 4055 0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c,
philpem@5 4056 0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000,
philpem@5 4057 0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0,
philpem@5 4058 0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e,
philpem@5 4059 0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c,
philpem@5 4060 0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0,
philpem@5 4061 0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,
philpem@5 4062 0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0,
philpem@5 4063 0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,
philpem@5 4064 0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000,
philpem@5 4065 0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800,
philpem@5 4066 0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4067 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1,
philpem@5 4068 0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff,
philpem@5 4069 0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000,
philpem@5 4070 0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000,
philpem@5 4071 0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000,
philpem@5 4072 0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000,
philpem@5 4073 0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003,
philpem@5 4074 0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce,
philpem@5 4075 0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00,
philpem@5 4076 0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f,
philpem@5 4077 0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,
philpem@5 4078 0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,
philpem@5 4079 0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800,
philpem@5 4080 0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,
philpem@5 4081 0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,0x7803c007,0x801f000f,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4082 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007,
philpem@5 4083 0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00,
philpem@5 4084 0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,
philpem@5 4085 0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0,
philpem@5 4086 0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0,
philpem@5 4087 0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00,
philpem@5 4088 0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000,
philpem@5 4089 0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000,
philpem@5 4090 0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f,
philpem@5 4091 0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0,
philpem@5 4092 0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007,
philpem@5 4093 0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,
philpem@5 4094 0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0,
philpem@5 4095 0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,
philpem@5 4096 0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00,
philpem@5 4097 0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4098 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,
philpem@5 4099 0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0,
philpem@5 4100 0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e,
philpem@5 4101 0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c,
philpem@5 4102 0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f,
philpem@5 4103 0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c,
philpem@5 4104 0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003,
philpem@5 4105 0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000,
philpem@5 4106 0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303,
philpem@5 4107 0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc,
philpem@5 4108 0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,
philpem@5 4109 0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780,
philpem@5 4110 0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000,
philpem@5 4111 0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078,
philpem@5 4112 0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4113 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00007,
philpem@5 4114 0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00,
philpem@5 4115 0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,
philpem@5 4116 0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0,
philpem@5 4117 0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,
philpem@5 4118 0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000,
philpem@5 4119 0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000,
philpem@5 4120 0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000,
philpem@5 4121 0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800,
philpem@5 4122 0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0,
philpem@5 4123 0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000,
philpem@5 4124 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,
philpem@5 4125 0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003,
philpem@5 4126 0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,
philpem@5 4127 0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f,
philpem@5 4128 0x1e0007,0x807c07c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4129 0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3,
philpem@5 4130 0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070,
philpem@5 4131 0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0,
philpem@5 4132 0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0,
philpem@5 4133 0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,
philpem@5 4134 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0,
philpem@5 4135 0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000,
philpem@5 4136 0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80,
philpem@5 4137 0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303,
philpem@5 4138 0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00,
philpem@5 4139 0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
philpem@5 4140 0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000,
philpem@5 4141 0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe,
philpem@5 4142 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,
philpem@5 4143 0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4144 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f,
philpem@5 4145 0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f,
philpem@5 4146 0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,
philpem@5 4147 0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800,
philpem@5 4148 0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,
philpem@5 4149 0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003,
philpem@5 4150 0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0,
philpem@5 4151 0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00,
philpem@5 4152 0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00,
philpem@5 4153 0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,
philpem@5 4154 0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000,
philpem@5 4155 0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,
philpem@5 4156 0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01,
philpem@5 4157 0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,
philpem@5 4158 0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800,
philpem@5 4159 0x7800f01e,0x1e0007,0x803c0780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4160 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,
philpem@5 4161 0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070,
philpem@5 4162 0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0,
philpem@5 4163 0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,
philpem@5 4164 0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e,
philpem@5 4165 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0,
philpem@5 4166 0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff,
philpem@5 4167 0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001,
philpem@5 4168 0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000,
philpem@5 4169 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801,
philpem@5 4170 0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
philpem@5 4171 0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000,
philpem@5 4172 0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe,
philpem@5 4173 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
philpem@5 4174 0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4175 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000,
philpem@5 4176 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000,
philpem@5 4177 0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800,
philpem@5 4178 0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000,
philpem@5 4179 0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
philpem@5 4180 0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800,
philpem@5 4181 0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,
philpem@5 4182 0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078,
philpem@5 4183 0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000,
philpem@5 4184 0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0,
philpem@5 4185 0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,
philpem@5 4186 0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0,
philpem@5 4187 0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000,
philpem@5 4188 0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,
philpem@5 4189 0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4190 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xffff8000,0x303c0001,
philpem@5 4191 0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e,
philpem@5 4192 0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,
philpem@5 4193 0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001,
philpem@5 4194 0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,
philpem@5 4195 0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000,
philpem@5 4196 0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003,
philpem@5 4197 0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff,
philpem@5 4198 0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00,
philpem@5 4199 0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80,
philpem@5 4200 0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,
philpem@5 4201 0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00,
philpem@5 4202 0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000,
philpem@5 4203 0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,
philpem@5 4204 0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4205 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000,
philpem@5 4206 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,
philpem@5 4207 0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800,
philpem@5 4208 0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001,
philpem@5 4209 0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00,
philpem@5 4210 0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003,
philpem@5 4211 0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001,
philpem@5 4212 0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800,
philpem@5 4213 0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000,
philpem@5 4214 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03,
philpem@5 4215 0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,
philpem@5 4216 0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000,
philpem@5 4217 0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000,
philpem@5 4218 0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c,
philpem@5 4219 0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4220 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00,
philpem@5 4221 0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff,
philpem@5 4222 0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e,
philpem@5 4223 0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c,
philpem@5 4224 0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f,
philpem@5 4225 0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e,
philpem@5 4226 0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f,
philpem@5 4227 0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000,
philpem@5 4228 0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,
philpem@5 4229 0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807,
philpem@5 4230 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f,
philpem@5 4231 0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,
philpem@5 4232 0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,
philpem@5 4233 0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800,
philpem@5 4234 0x78003e78,0x1e000f,0x800f9e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4235 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00,
philpem@5 4236 0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03,
philpem@5 4237 0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800,
philpem@5 4238 0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
philpem@5 4239 0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
philpem@5 4240 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,
philpem@5 4241 0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff,
philpem@5 4242 0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c,
philpem@5 4243 0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81,
philpem@5 4244 0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000,
philpem@5 4245 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0,
philpem@5 4246 0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c,
philpem@5 4247 0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,
philpem@5 4248 0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f,
philpem@5 4249 0x7be00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4250 0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e,
philpem@5 4251 0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03,
philpem@5 4252 0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780,
philpem@5 4253 0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01,
philpem@5 4254 0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,
philpem@5 4255 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,
philpem@5 4256 0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f,
philpem@5 4257 0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000,
philpem@5 4258 0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00,
philpem@5 4259 0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
philpem@5 4260 0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f,
philpem@5 4261 0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,
philpem@5 4262 0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,
philpem@5 4263 0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0,
philpem@5 4264 0x1f000f,0x7bc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4265 0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
philpem@5 4266 0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000,
philpem@5 4267 0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e,
philpem@5 4268 0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf,
philpem@5 4269 0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f,
philpem@5 4270 0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e,
philpem@5 4271 0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000,
philpem@5 4272 0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000,
philpem@5 4273 0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,
philpem@5 4274 0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,
philpem@5 4275 0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e,
philpem@5 4276 0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80,
philpem@5 4277 0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000,
philpem@5 4278 0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00,
philpem@5 4279 0xf8001ff0,0x1f801f,0x7fc00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4280 0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078,
philpem@5 4281 0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000,
philpem@5 4282 0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e,
philpem@5 4283 0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf,
philpem@5 4284 0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f,
philpem@5 4285 0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e,
philpem@5 4286 0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000,
philpem@5 4287 0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0,
philpem@5 4288 0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0,
philpem@5 4289 0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00,
philpem@5 4290 0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007,
philpem@5 4291 0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c,
philpem@5 4292 0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000,
philpem@5 4293 0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0,
philpem@5 4294 0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4295 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0,
philpem@5 4296 0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007,
philpem@5 4297 0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0,
philpem@5 4298 0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f,
philpem@5 4299 0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007,
philpem@5 4300 0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000,
philpem@5 4301 0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018,
philpem@5 4302 0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0,
philpem@5 4303 0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00,
philpem@5 4304 0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070,
philpem@5 4305 0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,
philpem@5 4306 0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8,
philpem@5 4307 0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80,
philpem@5 4308 0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0,
philpem@5 4309 0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0,
philpem@5 4310 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x780007f,
philpem@5 4311 0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780,
philpem@5 4312 0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff,
philpem@5 4313 0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000,
philpem@5 4314 0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000,
philpem@5 4315 0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff,
philpem@5 4316 0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000,
philpem@5 4317 0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f,
philpem@5 4318 0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000,
philpem@5 4319 0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1,
philpem@5 4320 0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,
philpem@5 4321 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f,
philpem@5 4322 0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff,
philpem@5 4323 0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8,
philpem@5 4324 0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0,
philpem@5 4325 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0x700003f,
philpem@5 4326 0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780,
philpem@5 4327 0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff,
philpem@5 4328 0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000,
philpem@5 4329 0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000,
philpem@5 4330 0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff,
philpem@5 4331 0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000,
philpem@5 4332 0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007,
philpem@5 4333 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7,
philpem@5 4334 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381,
philpem@5 4335 0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,
philpem@5 4336 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f,
philpem@5 4337 0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3,
philpem@5 4338 0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0,
philpem@5 4339 0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,0x1f000,0x0,0x0,0x0,0x0,
philpem@5 4340 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003,
philpem@5 4341 0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780,
philpem@5 4342 0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff,
philpem@5 4343 0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000,
philpem@5 4344 0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000,
philpem@5 4345 0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff,
philpem@5 4346 0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000,
philpem@5 4347 0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002,
philpem@5 4348 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7,
philpem@5 4349 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff,
philpem@5 4350 0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,
philpem@5 4351 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007,
philpem@5 4352 0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1,
philpem@5 4353 0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0,
philpem@5 4354 0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,0x1f000,0x0,0x0,0x0,0x0,0x0,
philpem@5 4355 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
philpem@5 4356 0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000,
philpem@5 4357 0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000,
philpem@5 4358 0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000,
philpem@5 4359 0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e,
philpem@5 4360 0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4361 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0,
philpem@5 4362 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0,
philpem@5 4363 0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f,
philpem@5 4364 0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800,
philpem@5 4365 0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0,
philpem@5 4366 0x1e1fc0,0x1f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4367 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4368 0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xe0000000,0x0,0x0,0x0,
philpem@5 4369 0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,
philpem@5 4370 0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,0x0,0x0,0x0,
philpem@5 4371 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3c0f,0x80000000,
philpem@5 4372 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0,
philpem@5 4373 0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4374 0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x0,0x0,0x0,0x780,0x1e0000,0x1e000,0x0,0x0,0x0,
philpem@5 4375 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,
philpem@5 4376 0x0,0x0,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000,
philpem@5 4377 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x1,0xe00001e0,0x0,
philpem@5 4378 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf8000000,
philpem@5 4379 0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4380 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4381 0x0,0x3c00000,0xe1c00,0x0,0x1c00000,0x0,0x0,0x1,0xc00001e0,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4382 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4383 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf80,0x1e0000,0x3e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4384 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x3c000,0x0,0x0,0x1f00000,
philpem@5 4385 0x0,0x780,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0xfe0100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4386 0x0,0x0,0x0,0x0,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0xf0007fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe0000000,
philpem@5 4387 0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0,
philpem@5 4388 0x78000000,0xf0000070,0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4389 0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x3ffe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,
philpem@5 4390 0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4391 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4392 0x0,0x0,0x0,0xf00,0x1e0000,0x3c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4393 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0x1e0,0x7c000,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4394 0x0,0x0,0x0,0x0,0x0,0x78,0x0,0x0,0x0,0x0,0x7fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,
philpem@5 4395 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0,
philpem@5 4396 0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0,
philpem@5 4397 0x1c000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,
philpem@5 4398 0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,0x0,0x0,0x1,0xc00003ff,
philpem@5 4399 0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4400 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00,0x1e0000,
philpem@5 4401 0x7c000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4402 0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,0xf0,0x78000,0x0,0x0,0x3e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,
philpem@5 4403 0x0,0x0,0x0,0x1fff80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,
philpem@5 4404 0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
philpem@5 4405 0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4406 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4407 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,
philpem@5 4408 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f,0x0,
philpem@5 4409 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3e00,0x1e0000,0xf8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4410 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000,0x0,0x0,
philpem@5 4411 0xf8,0xf8000,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x1fe00,0x0,0x0,0x0,0x0,
philpem@5 4412 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4413 0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0,
philpem@5 4414 0x3fe00,0x0,0x0,0x0,0x0,0x600001ff,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4415 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180000,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,
philpem@5 4416 0x3fe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4417 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4418 0x0,0x0,0x0,0x0,0x7fe00,0x1e0000,0x1ff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4419 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4420 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4421 0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,
philpem@5 4422 0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4423 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4424 0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3fc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,
philpem@5 4425 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fe,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4426 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fc00,0x1e0000,0x1ff0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4427 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4428 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4429 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x3ffe,0x0,0x0,0x3ff8000,0x0,0x0,0x0,
philpem@5 4430 0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0,
philpem@5 4431 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4432 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,
philpem@5 4433 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0,0x0,
philpem@5 4434 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f800,0x1e0000,0x1fe0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4435 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4436 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4437 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f8,0x0,0x0,0x3fe0000,
philpem@5 4438 0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7e,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4439 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4440 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4441 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4442 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7e000,0x1e0000,0x1f80000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4443 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4444 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4445 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4446 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4447 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4448 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4449 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4450 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4451 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4452 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4453 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0,0x0,0x0,0x0,
philpem@5 4454 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4455 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4456 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
philpem@5 4457 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 };
philpem@5 4458
philpem@5 4459 // Definition of a 40x38 'danger' color logo.
philpem@5 4460 const unsigned char logo40x38[4576] = {
philpem@5 4461 177,200,200,200,3,123,123,0,36,200,200,200,1,123,123,0,2,255,255,0,1,189,189,189,1,0,0,0,34,200,200,200,
philpem@5 4462 1,123,123,0,4,255,255,0,1,189,189,189,1,0,0,0,1,123,123,123,32,200,200,200,1,123,123,0,5,255,255,0,1,0,0,
philpem@5 4463 0,2,123,123,123,30,200,200,200,1,123,123,0,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,29,200,200,200,
philpem@5 4464 1,123,123,0,7,255,255,0,1,0,0,0,2,123,123,123,28,200,200,200,1,123,123,0,8,255,255,0,1,189,189,189,1,0,0,0,
philpem@5 4465 2,123,123,123,27,200,200,200,1,123,123,0,9,255,255,0,1,0,0,0,2,123,123,123,26,200,200,200,1,123,123,0,10,255,
philpem@5 4466 255,0,1,189,189,189,1,0,0,0,2,123,123,123,25,200,200,200,1,123,123,0,3,255,255,0,1,189,189,189,3,0,0,0,1,189,
philpem@5 4467 189,189,3,255,255,0,1,0,0,0,2,123,123,123,24,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,3,255,255,0,1,189,
philpem@5 4468 189,189,1,0,0,0,2,123,123,123,23,200,200,200,1,123,123,0,4,255,255,0,5,0,0,0,4,255,255,0,1,0,0,0,2,123,123,123,
philpem@5 4469 22,200,200,200,1,123,123,0,5,255,255,0,5,0,0,0,4,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,21,200,200,200,
philpem@5 4470 1,123,123,0,5,255,255,0,5,0,0,0,5,255,255,0,1,0,0,0,2,123,123,123,20,200,200,200,1,123,123,0,6,255,255,0,5,0,0,
philpem@5 4471 0,5,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,19,200,200,200,1,123,123,0,6,255,255,0,1,123,123,0,3,0,0,0,1,
philpem@5 4472 123,123,0,6,255,255,0,1,0,0,0,2,123,123,123,18,200,200,200,1,123,123,0,7,255,255,0,1,189,189,189,3,0,0,0,1,189,
philpem@5 4473 189,189,6,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,17,200,200,200,1,123,123,0,8,255,255,0,3,0,0,0,8,255,255,
philpem@5 4474 0,1,0,0,0,2,123,123,123,16,200,200,200,1,123,123,0,9,255,255,0,1,123,123,0,1,0,0,0,1,123,123,0,8,255,255,0,1,189,
philpem@5 4475 189,189,1,0,0,0,2,123,123,123,15,200,200,200,1,123,123,0,9,255,255,0,1,189,189,189,1,0,0,0,1,189,189,189,9,255,255,
philpem@5 4476 0,1,0,0,0,2,123,123,123,14,200,200,200,1,123,123,0,11,255,255,0,1,0,0,0,10,255,255,0,1,189,189,189,1,0,0,0,2,123,
philpem@5 4477 123,123,13,200,200,200,1,123,123,0,23,255,255,0,1,0,0,0,2,123,123,123,12,200,200,200,1,123,123,0,11,255,255,0,1,189,
philpem@5 4478 189,189,2,0,0,0,1,189,189,189,9,255,255,0,1,189,189,189,1,0,0,0,2,123,123,123,11,200,200,200,1,123,123,0,11,255,255,
philpem@5 4479 0,4,0,0,0,10,255,255,0,1,0,0,0,2,123,123,123,10,200,200,200,1,123,123,0,12,255,255,0,4,0,0,0,10,255,255,0,1,189,189,
philpem@5 4480 189,1,0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,12,255,255,0,1,189,189,189,2,0,0,0,1,189,189,189,11,255,255,0,1,
philpem@5 4481 0,0,0,2,123,123,123,9,200,200,200,1,123,123,0,27,255,255,0,1,0,0,0,3,123,123,123,8,200,200,200,1,123,123,0,26,255,
philpem@5 4482 255,0,1,189,189,189,1,0,0,0,3,123,123,123,9,200,200,200,1,123,123,0,24,255,255,0,1,189,189,189,1,0,0,0,4,123,123,
philpem@5 4483 123,10,200,200,200,1,123,123,0,24,0,0,0,5,123,123,123,12,200,200,200,27,123,123,123,14,200,200,200,25,123,123,123,86,
philpem@5 4484 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0};
philpem@5 4485
philpem@5 4486 //! Display a warning message.
philpem@5 4487 /**
philpem@5 4488 \param format is a C-string describing the format of the message, as in <tt>std::printf()</tt>.
philpem@5 4489 **/
philpem@5 4490 inline void warn(const char *format, ...) {
philpem@5 4491 if (cimg::exception_mode()>=1) {
philpem@5 4492 char message[8192];
philpem@5 4493 cimg_std::va_list ap;
philpem@5 4494 va_start(ap,format);
philpem@5 4495 cimg_std::vsprintf(message,format,ap);
philpem@5 4496 va_end(ap);
philpem@5 4497 #ifdef cimg_strict_warnings
philpem@5 4498 throw CImgWarningException(message);
philpem@5 4499 #else
philpem@5 4500 cimg_std::fprintf(cimg_stdout,"\n%s# CImg Warning%s :\n%s\n",cimg::t_red,cimg::t_normal,message);
philpem@5 4501 #endif
philpem@5 4502 }
philpem@5 4503 }
philpem@5 4504
philpem@5 4505 // Execute an external system command.
philpem@5 4506 /**
philpem@5 4507 \note This function is similar to <tt>std::system()</tt>
philpem@5 4508 and is here because using the <tt>std::</tt> version on
philpem@5 4509 Windows may open undesired consoles.
philpem@5 4510 **/
philpem@5 4511 inline int system(const char *const command, const char *const module_name=0) {
philpem@5 4512 #if cimg_OS==2
philpem@5 4513 PROCESS_INFORMATION pi;
philpem@5 4514 STARTUPINFO si;
philpem@5 4515 cimg_std::memset(&pi,0,sizeof(PROCESS_INFORMATION));
philpem@5 4516 cimg_std::memset(&si,0,sizeof(STARTUPINFO));
philpem@5 4517 GetStartupInfo(&si);
philpem@5 4518 si.cb = sizeof(si);
philpem@5 4519 si.wShowWindow = SW_HIDE;
philpem@5 4520 si.dwFlags |= SW_HIDE;
philpem@5 4521 const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi);
philpem@5 4522 if (res) {
philpem@5 4523 WaitForSingleObject(pi.hProcess, INFINITE);
philpem@5 4524 CloseHandle(pi.hThread);
philpem@5 4525 CloseHandle(pi.hProcess);
philpem@5 4526 return 0;
philpem@5 4527 } else
philpem@5 4528 #endif
philpem@5 4529 return cimg_std::system(command);
philpem@5 4530 return module_name?0:1;
philpem@5 4531 }
philpem@5 4532
philpem@5 4533 //! Return a reference to a temporary variable of type T.
philpem@5 4534 template<typename T>
philpem@5 4535 inline T& temporary(const T&) {
philpem@5 4536 static T temp;
philpem@5 4537 return temp;
philpem@5 4538 }
philpem@5 4539
philpem@5 4540 //! Exchange values of variables \p a and \p b.
philpem@5 4541 template<typename T>
philpem@5 4542 inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
philpem@5 4543
philpem@5 4544 //! Exchange values of variables (\p a1,\p a2) and (\p b1,\p b2).
philpem@5 4545 template<typename T1, typename T2>
philpem@5 4546 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) {
philpem@5 4547 cimg::swap(a1,b1); cimg::swap(a2,b2);
philpem@5 4548 }
philpem@5 4549
philpem@5 4550 //! Exchange values of variables (\p a1,\p a2,\p a3) and (\p b1,\p b2,\p b3).
philpem@5 4551 template<typename T1, typename T2, typename T3>
philpem@5 4552 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) {
philpem@5 4553 cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3);
philpem@5 4554 }
philpem@5 4555
philpem@5 4556 //! Exchange values of variables (\p a1,\p a2,...,\p a4) and (\p b1,\p b2,...,\p b4).
philpem@5 4557 template<typename T1, typename T2, typename T3, typename T4>
philpem@5 4558 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) {
philpem@5 4559 cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4);
philpem@5 4560 }
philpem@5 4561
philpem@5 4562 //! Exchange values of variables (\p a1,\p a2,...,\p a5) and (\p b1,\p b2,...,\p b5).
philpem@5 4563 template<typename T1, typename T2, typename T3, typename T4, typename T5>
philpem@5 4564 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) {
philpem@5 4565 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5);
philpem@5 4566 }
philpem@5 4567
philpem@5 4568 //! Exchange values of variables (\p a1,\p a2,...,\p a6) and (\p b1,\p b2,...,\p b6).
philpem@5 4569 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
philpem@5 4570 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) {
philpem@5 4571 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6);
philpem@5 4572 }
philpem@5 4573
philpem@5 4574 //! Exchange values of variables (\p a1,\p a2,...,\p a7) and (\p b1,\p b2,...,\p b7).
philpem@5 4575 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
philpem@5 4576 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
philpem@5 4577 T7& a7, T7& b7) {
philpem@5 4578 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7);
philpem@5 4579 }
philpem@5 4580
philpem@5 4581 //! Exchange values of variables (\p a1,\p a2,...,\p a8) and (\p b1,\p b2,...,\p b8).
philpem@5 4582 template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
philpem@5 4583 inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6,
philpem@5 4584 T7& a7, T7& b7, T8& a8, T8& b8) {
philpem@5 4585 cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8);
philpem@5 4586 }
philpem@5 4587
philpem@5 4588 //! Return the current endianness of the CPU.
philpem@5 4589 /**
philpem@5 4590 \return \c false for "Little Endian", \c true for "Big Endian".
philpem@5 4591 **/
philpem@5 4592 inline bool endianness() {
philpem@5 4593 const int x = 1;
philpem@5 4594 return ((unsigned char*)&x)[0]?false:true;
philpem@5 4595 }
philpem@5 4596
philpem@5 4597 //! Invert endianness of a memory buffer.
philpem@5 4598 template<typename T>
philpem@5 4599 inline void invert_endianness(T* const buffer, const unsigned int size) {
philpem@5 4600 if (size) switch (sizeof(T)) {
philpem@5 4601 case 1 : break;
philpem@5 4602 case 2 : { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer; ) {
philpem@5 4603 const unsigned short val = *(--ptr);
philpem@5 4604 *ptr = (unsigned short)((val>>8)|((val<<8)));
philpem@5 4605 }} break;
philpem@5 4606 case 4 : { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer; ) {
philpem@5 4607 const unsigned int val = *(--ptr);
philpem@5 4608 *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24);
philpem@5 4609 }} break;
philpem@5 4610 default : { for (T* ptr = buffer+size; ptr>buffer; ) {
philpem@5 4611 unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T);
philpem@5 4612 for (int i=0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe));
philpem@5 4613 }}
philpem@5 4614 }
philpem@5 4615 }
philpem@5 4616
philpem@5 4617 //! Invert endianness of a single variable.
philpem@5 4618 template<typename T>
philpem@5 4619 inline T& invert_endianness(T& a) {
philpem@5 4620 invert_endianness(&a,1);
philpem@5 4621 return a;
philpem@5 4622 }
philpem@5 4623
philpem@5 4624 //! Get the value of a system timer with a millisecond precision.
philpem@5 4625 inline unsigned long time() {
philpem@5 4626 #if cimg_OS==1
philpem@5 4627 struct timeval st_time;
philpem@5 4628 gettimeofday(&st_time,0);
philpem@5 4629 return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000);
philpem@5 4630 #elif cimg_OS==2
philpem@5 4631 static SYSTEMTIME st_time;
philpem@5 4632 GetSystemTime(&st_time);
philpem@5 4633 return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour)));
philpem@5 4634 #else
philpem@5 4635 return 0;
philpem@5 4636 #endif
philpem@5 4637 }
philpem@5 4638
philpem@5 4639 //! Sleep for a certain numbers of milliseconds.
philpem@5 4640 /**
philpem@5 4641 This function frees the CPU ressources during the sleeping time.
philpem@5 4642 It may be used to temporize your program properly, without wasting CPU time.
philpem@5 4643 **/
philpem@5 4644 inline void sleep(const unsigned int milliseconds) {
philpem@5 4645 #if cimg_OS==1
philpem@5 4646 struct timespec tv;
philpem@5 4647 tv.tv_sec = milliseconds/1000;
philpem@5 4648 tv.tv_nsec = (milliseconds%1000)*1000000;
philpem@5 4649 nanosleep(&tv,0);
philpem@5 4650 #elif cimg_OS==2
philpem@5 4651 Sleep(milliseconds);
philpem@5 4652 #endif
philpem@5 4653 }
philpem@5 4654
philpem@5 4655 inline unsigned int _sleep(const unsigned int milliseconds, unsigned long& timer) {
philpem@5 4656 if (!timer) timer = cimg::time();
philpem@5 4657 const unsigned long current_time = cimg::time();
philpem@5 4658 if (current_time>=timer+milliseconds) { timer = current_time; return 0; }
philpem@5 4659 const unsigned long time_diff = timer + milliseconds - current_time;
philpem@5 4660 timer = current_time + time_diff;
philpem@5 4661 cimg::sleep(time_diff);
philpem@5 4662 return (unsigned int)time_diff;
philpem@5 4663 }
philpem@5 4664
philpem@5 4665 //! Wait for a certain number of milliseconds since the last call.
philpem@5 4666 /**
philpem@5 4667 This function is equivalent to sleep() but the waiting time is computed with regard to the last call
philpem@5 4668 of wait(). It may be used to temporize your program properly.
philpem@5 4669 **/
philpem@5 4670 inline unsigned int wait(const unsigned int milliseconds) {
philpem@5 4671 static unsigned long timer = 0;
philpem@5 4672 if (!timer) timer = cimg::time();
philpem@5 4673 return _sleep(milliseconds,timer);
philpem@5 4674 }
philpem@5 4675
philpem@5 4676 // Use a specific srand initialization to avoid multi-threads to have to the
philpem@5 4677 // same series of random numbers (executed only once for a single program).
philpem@5 4678 inline void srand() {
philpem@5 4679 static bool first_time = true;
philpem@5 4680 if (first_time) {
philpem@5 4681 cimg_std::srand(cimg::time());
philpem@5 4682 unsigned char *const rand_ptr = new unsigned char[1+cimg_std::rand()%2048];
philpem@5 4683 cimg_std::srand((unsigned int)cimg_std::rand() + *(unsigned int*)(void*)rand_ptr);
philpem@5 4684 delete[] rand_ptr;
philpem@5 4685 first_time = false;
philpem@5 4686 }
philpem@5 4687 }
philpem@5 4688
philpem@5 4689 //! Return a left bitwise-rotated number.
philpem@5 4690 template<typename T>
philpem@5 4691 inline const T rol(const T a, const unsigned int n=1) {
philpem@5 4692 return n?(T)((a<<n)|(a>>((sizeof(T)<<3)-n))):a;
philpem@5 4693 }
philpem@5 4694
philpem@5 4695 //! Return a right bitwise-rotated number.
philpem@5 4696 template<typename T>
philpem@5 4697 inline const T ror(const T a, const unsigned int n=1) {
philpem@5 4698 return n?(T)((a>>n)|(a<<((sizeof(T)<<3)-n))):a;
philpem@5 4699 }
philpem@5 4700
philpem@5 4701 //! Return the absolute value of a number.
philpem@5 4702 /**
philpem@5 4703 \note This function is different from <tt>std::abs()</tt> or <tt>std::fabs()</tt>
philpem@5 4704 because it is able to consider a variable of any type, without cast needed.
philpem@5 4705 **/
philpem@5 4706 template<typename T>
philpem@5 4707 inline T abs(const T a) {
philpem@5 4708 return a>=0?a:-a;
philpem@5 4709 }
philpem@5 4710 inline bool abs(const bool a) {
philpem@5 4711 return a;
philpem@5 4712 }
philpem@5 4713 inline unsigned char abs(const unsigned char a) {
philpem@5 4714 return a;
philpem@5 4715 }
philpem@5 4716 inline unsigned short abs(const unsigned short a) {
philpem@5 4717 return a;
philpem@5 4718 }
philpem@5 4719 inline unsigned int abs(const unsigned int a) {
philpem@5 4720 return a;
philpem@5 4721 }
philpem@5 4722 inline unsigned long abs(const unsigned long a) {
philpem@5 4723 return a;
philpem@5 4724 }
philpem@5 4725 inline double abs(const double a) {
philpem@5 4726 return cimg_std::fabs(a);
philpem@5 4727 }
philpem@5 4728 inline float abs(const float a) {
philpem@5 4729 return (float)cimg_std::fabs((double)a);
philpem@5 4730 }
philpem@5 4731 inline int abs(const int a) {
philpem@5 4732 return cimg_std::abs(a);
philpem@5 4733 }
philpem@5 4734
philpem@5 4735 //! Return the square of a number.
philpem@5 4736 template<typename T>
philpem@5 4737 inline T sqr(const T val) {
philpem@5 4738 return val*val;
philpem@5 4739 }
philpem@5 4740
philpem@5 4741 //! Return 1 + log_10(x).
philpem@5 4742 inline int xln(const int x) {
philpem@5 4743 return x>0?(int)(1+cimg_std::log10((double)x)):1;
philpem@5 4744 }
philpem@5 4745
philpem@5 4746 //! Return the minimum value between two numbers.
philpem@5 4747 template<typename t1, typename t2>
philpem@5 4748 inline typename cimg::superset<t1,t2>::type min(const t1& a, const t2& b) {
philpem@5 4749 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 4750 return (t1t2)(a<=b?a:b);
philpem@5 4751 }
philpem@5 4752
philpem@5 4753 //! Return the minimum value between three numbers.
philpem@5 4754 template<typename t1, typename t2, typename t3>
philpem@5 4755 inline typename cimg::superset2<t1,t2,t3>::type min(const t1& a, const t2& b, const t3& c) {
philpem@5 4756 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
philpem@5 4757 return (t1t2t3)cimg::min(cimg::min(a,b),c);
philpem@5 4758 }
philpem@5 4759
philpem@5 4760 //! Return the minimum value between four numbers.
philpem@5 4761 template<typename t1, typename t2, typename t3, typename t4>
philpem@5 4762 inline typename cimg::superset3<t1,t2,t3,t4>::type min(const t1& a, const t2& b, const t3& c, const t4& d) {
philpem@5 4763 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
philpem@5 4764 return (t1t2t3t4)cimg::min(cimg::min(a,b,c),d);
philpem@5 4765 }
philpem@5 4766
philpem@5 4767 //! Return the maximum value between two numbers.
philpem@5 4768 template<typename t1, typename t2>
philpem@5 4769 inline typename cimg::superset<t1,t2>::type max(const t1& a, const t2& b) {
philpem@5 4770 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 4771 return (t1t2)(a>=b?a:b);
philpem@5 4772 }
philpem@5 4773
philpem@5 4774 //! Return the maximum value between three numbers.
philpem@5 4775 template<typename t1, typename t2, typename t3>
philpem@5 4776 inline typename cimg::superset2<t1,t2,t3>::type max(const t1& a, const t2& b, const t3& c) {
philpem@5 4777 typedef typename cimg::superset2<t1,t2,t3>::type t1t2t3;
philpem@5 4778 return (t1t2t3)cimg::max(cimg::max(a,b),c);
philpem@5 4779 }
philpem@5 4780
philpem@5 4781 //! Return the maximum value between four numbers.
philpem@5 4782 template<typename t1, typename t2, typename t3, typename t4>
philpem@5 4783 inline typename cimg::superset3<t1,t2,t3,t4>::type max(const t1& a, const t2& b, const t3& c, const t4& d) {
philpem@5 4784 typedef typename cimg::superset3<t1,t2,t3,t4>::type t1t2t3t4;
philpem@5 4785 return (t1t2t3t4)cimg::max(cimg::max(a,b,c),d);
philpem@5 4786 }
philpem@5 4787
philpem@5 4788 //! Return the sign of a number.
philpem@5 4789 template<typename T>
philpem@5 4790 inline T sign(const T x) {
philpem@5 4791 return (x<0)?(T)(-1):(x==0?(T)0:(T)1);
philpem@5 4792 }
philpem@5 4793
philpem@5 4794 //! Return the nearest power of 2 higher than a given number.
philpem@5 4795 template<typename T>
philpem@5 4796 inline unsigned long nearest_pow2(const T x) {
philpem@5 4797 unsigned long i = 1;
philpem@5 4798 while (x>i) i<<=1;
philpem@5 4799 return i;
philpem@5 4800 }
philpem@5 4801
philpem@5 4802 //! Return the modulo of a number.
philpem@5 4803 /**
philpem@5 4804 \note This modulo function accepts negative and floating-points modulo numbers, as well as
philpem@5 4805 variable of any type.
philpem@5 4806 **/
philpem@5 4807 template<typename T>
philpem@5 4808 inline T mod(const T& x, const T& m) {
philpem@5 4809 const double dx = (double)x, dm = (double)m;
philpem@5 4810 if (x<0) { return (T)(dm+dx+dm*cimg_std::floor(-dx/dm)); }
philpem@5 4811 return (T)(dx-dm*cimg_std::floor(dx/dm));
philpem@5 4812 }
philpem@5 4813 inline int mod(const bool x, const bool m) {
philpem@5 4814 return m?(x?1:0):0;
philpem@5 4815 }
philpem@5 4816 inline int mod(const char x, const char m) {
philpem@5 4817 return x>=0?x%m:(x%m?m+x%m:0);
philpem@5 4818 }
philpem@5 4819 inline int mod(const short x, const short m) {
philpem@5 4820 return x>=0?x%m:(x%m?m+x%m:0);
philpem@5 4821 }
philpem@5 4822 inline int mod(const int x, const int m) {
philpem@5 4823 return x>=0?x%m:(x%m?m+x%m:0);
philpem@5 4824 }
philpem@5 4825 inline int mod(const long x, const long m) {
philpem@5 4826 return x>=0?x%m:(x%m?m+x%m:0);
philpem@5 4827 }
philpem@5 4828 inline int mod(const unsigned char x, const unsigned char m) {
philpem@5 4829 return x%m;
philpem@5 4830 }
philpem@5 4831 inline int mod(const unsigned short x, const unsigned short m) {
philpem@5 4832 return x%m;
philpem@5 4833 }
philpem@5 4834 inline int mod(const unsigned int x, const unsigned int m) {
philpem@5 4835 return x%m;
philpem@5 4836 }
philpem@5 4837 inline int mod(const unsigned long x, const unsigned long m) {
philpem@5 4838 return x%m;
philpem@5 4839 }
philpem@5 4840
philpem@5 4841 //! Return the minmod of two numbers.
philpem@5 4842 /**
philpem@5 4843 <i>minmod(\p a,\p b)</i> is defined to be :
philpem@5 4844 - <i>minmod(\p a,\p b) = min(\p a,\p b)</i>, if \p a and \p b have the same sign.
philpem@5 4845 - <i>minmod(\p a,\p b) = 0</i>, if \p a and \p b have different signs.
philpem@5 4846 **/
philpem@5 4847 template<typename T>
philpem@5 4848 inline T minmod(const T a, const T b) {
philpem@5 4849 return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a));
philpem@5 4850 }
philpem@5 4851
philpem@5 4852 //! Return a random variable between [0,1] with respect to an uniform distribution.
philpem@5 4853 inline double rand() {
philpem@5 4854 static bool first_time = true;
philpem@5 4855 if (first_time) { cimg::srand(); first_time = false; }
philpem@5 4856 return (double)cimg_std::rand()/RAND_MAX;
philpem@5 4857 }
philpem@5 4858
philpem@5 4859 //! Return a random variable between [-1,1] with respect to an uniform distribution.
philpem@5 4860 inline double crand() {
philpem@5 4861 return 1-2*cimg::rand();
philpem@5 4862 }
philpem@5 4863
philpem@5 4864 //! Return a random variable following a gaussian distribution and a standard deviation of 1.
philpem@5 4865 inline double grand() {
philpem@5 4866 double x1, w;
philpem@5 4867 do {
philpem@5 4868 const double x2 = 2*cimg::rand() - 1.0;
philpem@5 4869 x1 = 2*cimg::rand()-1.0;
philpem@5 4870 w = x1*x1 + x2*x2;
philpem@5 4871 } while (w<=0 || w>=1.0);
philpem@5 4872 return x1*cimg_std::sqrt((-2*cimg_std::log(w))/w);
philpem@5 4873 }
philpem@5 4874
philpem@5 4875 //! Return a random variable following a Poisson distribution of parameter z.
philpem@5 4876 inline unsigned int prand(const double z) {
philpem@5 4877 if (z<=1.0e-10) return 0;
philpem@5 4878 if (z>100.0) return (unsigned int)((std::sqrt(z) * cimg::grand()) + z);
philpem@5 4879 unsigned int k = 0;
philpem@5 4880 const double y = std::exp(-z);
philpem@5 4881 for (double s = 1.0; s>=y; ++k) s*=cimg::rand();
philpem@5 4882 return k-1;
philpem@5 4883 }
philpem@5 4884
philpem@5 4885 //! Return a rounded number.
philpem@5 4886 /**
philpem@5 4887 \param x is the number to be rounded.
philpem@5 4888 \param y is the rounding precision.
philpem@5 4889 \param rounding_type defines the type of rounding (0=nearest, -1=backward, 1=forward).
philpem@5 4890 **/
philpem@5 4891 inline double round(const double x, const double y, const int rounding_type=0) {
philpem@5 4892 if (y<=0) return x;
philpem@5 4893 const double delta = cimg::mod(x,y);
philpem@5 4894 if (delta==0.0) return x;
philpem@5 4895 const double
philpem@5 4896 backward = x - delta,
philpem@5 4897 forward = backward + y;
philpem@5 4898 return rounding_type<0?backward:(rounding_type>0?forward:(2*delta<y?backward:forward));
philpem@5 4899 }
philpem@5 4900
philpem@5 4901 inline double _pythagore(double a, double b) {
philpem@5 4902 const double absa = cimg::abs(a), absb = cimg::abs(b);
philpem@5 4903 if (absa>absb) { const double tmp = absb/absa; return absa*cimg_std::sqrt(1.0+tmp*tmp); }
philpem@5 4904 else { const double tmp = absa/absb; return (absb==0?0:absb*cimg_std::sqrt(1.0+tmp*tmp)); }
philpem@5 4905 }
philpem@5 4906
philpem@5 4907 //! Remove the 'case' of an ASCII character.
philpem@5 4908 inline char uncase(const char x) {
philpem@5 4909 return (char)((x<'A'||x>'Z')?x:x-'A'+'a');
philpem@5 4910 }
philpem@5 4911
philpem@5 4912 //! Remove the 'case' of a C string.
philpem@5 4913 /**
philpem@5 4914 Acts in-place.
philpem@5 4915 **/
philpem@5 4916 inline void uncase(char *const string) {
philpem@5 4917 if (string) for (char *ptr = string; *ptr; ++ptr) *ptr = uncase(*ptr);
philpem@5 4918 }
philpem@5 4919
philpem@5 4920 //! Read a float number from a C-string.
philpem@5 4921 /**
philpem@5 4922 \note This function is quite similar to <tt>std::atof()</tt>,
philpem@5 4923 but that it allows the retrieval of fractions as in "1/2".
philpem@5 4924 **/
philpem@5 4925 inline float atof(const char *const str) {
philpem@5 4926 float x = 0,y = 1;
philpem@5 4927 if (!str) return 0; else { cimg_std::sscanf(str,"%g/%g",&x,&y); return x/y; }
philpem@5 4928 }
philpem@5 4929
philpem@5 4930 //! Compute the length of a C-string.
philpem@5 4931 /**
philpem@5 4932 \note This function is similar to <tt>std::strlen()</tt>
philpem@5 4933 and is here because some old compilers do not
philpem@5 4934 define the <tt>std::</tt> version.
philpem@5 4935 **/
philpem@5 4936 inline int strlen(const char *const s) {
philpem@5 4937 if (!s) return -1;
philpem@5 4938 int k = 0;
philpem@5 4939 for (const char *ns = s; *ns; ++ns) ++k;
philpem@5 4940 return k;
philpem@5 4941 }
philpem@5 4942
philpem@5 4943 //! Compare the first \p n characters of two C-strings.
philpem@5 4944 /**
philpem@5 4945 \note This function is similar to <tt>std::strncmp()</tt>
philpem@5 4946 and is here because some old compilers do not
philpem@5 4947 define the <tt>std::</tt> version.
philpem@5 4948 **/
philpem@5 4949 inline int strncmp(const char *const s1, const char *const s2, const int l) {
philpem@5 4950 if (!s1) return s2?-1:0;
philpem@5 4951 const char *ns1 = s1, *ns2 = s2;
philpem@5 4952 int k, diff = 0; for (k = 0; k<l && !(diff = *ns1-*ns2); ++k) { ++ns1; ++ns2; }
philpem@5 4953 return k!=l?diff:0;
philpem@5 4954 }
philpem@5 4955
philpem@5 4956 //! Compare the first \p n characters of two C-strings, ignoring the case.
philpem@5 4957 /**
philpem@5 4958 \note This function is similar to <tt>std::strncasecmp()</tt>
philpem@5 4959 and is here because some old compilers do not
philpem@5 4960 define the <tt>std::</tt> version.
philpem@5 4961 **/
philpem@5 4962 inline int strncasecmp(const char *const s1, const char *const s2, const int l) {
philpem@5 4963 if (!s1) return s2?-1:0;
philpem@5 4964 const char *ns1 = s1, *ns2 = s2;
philpem@5 4965 int k, diff = 0; for (k = 0; k<l && !(diff = uncase(*ns1)-uncase(*ns2)); ++k) { ++ns1; ++ns2; }
philpem@5 4966 return k!=l?diff:0;
philpem@5 4967 }
philpem@5 4968
philpem@5 4969 //! Compare two C-strings.
philpem@5 4970 /**
philpem@5 4971 \note This function is similar to <tt>std::strcmp()</tt>
philpem@5 4972 and is here because some old compilers do not
philpem@5 4973 define the <tt>std::</tt> version.
philpem@5 4974 **/
philpem@5 4975 inline int strcmp(const char *const s1, const char *const s2) {
philpem@5 4976 const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
philpem@5 4977 return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2));
philpem@5 4978 }
philpem@5 4979
philpem@5 4980 //! Compare two C-strings, ignoring the case.
philpem@5 4981 /**
philpem@5 4982 \note This function is similar to <tt>std::strcasecmp()</tt>
philpem@5 4983 and is here because some old compilers do not
philpem@5 4984 define the <tt>std::</tt> version.
philpem@5 4985 **/
philpem@5 4986 inline int strcasecmp(const char *const s1, const char *const s2) {
philpem@5 4987 const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2);
philpem@5 4988 return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2));
philpem@5 4989 }
philpem@5 4990
philpem@5 4991 //! Find a character in a C-string.
philpem@5 4992 inline int strfind(const char *const s, const char c) {
philpem@5 4993 if (!s) return -1;
philpem@5 4994 int l; for (l = cimg::strlen(s); l>=0 && s[l]!=c; --l) {}
philpem@5 4995 return l;
philpem@5 4996 }
philpem@5 4997
philpem@5 4998 //! Remove useless delimiters on the borders of a C-string
philpem@5 4999 inline bool strpare(char *const s, const char delimiter=' ', const bool symmetric=false) {
philpem@5 5000 if (!s) return false;
philpem@5 5001 const int l = cimg::strlen(s);
philpem@5 5002 int p, q;
philpem@5 5003 if (symmetric) for (p = 0, q = l-1; p<q && s[p]==delimiter && s[q]==delimiter; ++p) --q;
philpem@5 5004 else {
philpem@5 5005 for (p = 0; p<l && s[p]==delimiter; ) ++p;
philpem@5 5006 for (q = l-1; q>p && s[q]==delimiter; ) --q;
philpem@5 5007 }
philpem@5 5008 const int n = q - p + 1;
philpem@5 5009 if (n!=l) { cimg_std::memmove(s,s+p,n); s[n] = '\0'; return true; }
philpem@5 5010 return false;
philpem@5 5011 }
philpem@5 5012
philpem@5 5013 //! Remove useless spaces and symmetric delimiters ', " and ` from a C-string.
philpem@5 5014 inline void strclean(char *const s) {
philpem@5 5015 if (!s) return;
philpem@5 5016 strpare(s,' ',false);
philpem@5 5017 for (bool need_iter = true; need_iter; ) {
philpem@5 5018 need_iter = false;
philpem@5 5019 need_iter |= strpare(s,'\'',true);
philpem@5 5020 need_iter |= strpare(s,'\"',true);
philpem@5 5021 need_iter |= strpare(s,'`',true);
philpem@5 5022 }
philpem@5 5023 }
philpem@5 5024
philpem@5 5025 //! Replace explicit escape sequences '\x' in C-strings (where x in [ntvbrfa?'"0]).
philpem@5 5026 inline void strescape(char *const s) {
philpem@5 5027 #define cimg_strescape(ci,co) case ci: *nd = co; break;
philpem@5 5028 char *ns, *nd;
philpem@5 5029 for (ns = nd = s; *ns; ++ns, ++nd)
philpem@5 5030 if (*ns=='\\') switch (*(++ns)) {
philpem@5 5031 cimg_strescape('n','\n');
philpem@5 5032 cimg_strescape('t','\t');
philpem@5 5033 cimg_strescape('v','\v');
philpem@5 5034 cimg_strescape('b','\b');
philpem@5 5035 cimg_strescape('r','\r');
philpem@5 5036 cimg_strescape('f','\f');
philpem@5 5037 cimg_strescape('a','\a');
philpem@5 5038 cimg_strescape('\\','\\');
philpem@5 5039 cimg_strescape('\?','\?');
philpem@5 5040 cimg_strescape('\'','\'');
philpem@5 5041 cimg_strescape('\"','\"');
philpem@5 5042 cimg_strescape('\0','\0');
philpem@5 5043 }
philpem@5 5044 else *nd = *ns;
philpem@5 5045 *nd = 0;
philpem@5 5046 }
philpem@5 5047
philpem@5 5048 //! Compute the basename of a filename.
philpem@5 5049 inline const char* basename(const char *const s) {
philpem@5 5050 return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0);
philpem@5 5051 }
philpem@5 5052
philpem@5 5053 // Generate a random filename.
philpem@5 5054 inline const char* filenamerand() {
philpem@5 5055 static char id[9] = { 0,0,0,0,0,0,0,0,0 };
philpem@5 5056 cimg::srand();
philpem@5 5057 for (unsigned int k=0; k<8; ++k) {
philpem@5 5058 const int v = (int)cimg_std::rand()%3;
philpem@5 5059 id[k] = (char)(v==0?('0'+(cimg_std::rand()%10)):(v==1?('a'+(cimg_std::rand()%26)):('A'+(cimg_std::rand()%26))));
philpem@5 5060 }
philpem@5 5061 return id;
philpem@5 5062 }
philpem@5 5063
philpem@5 5064 // Convert filename into a Windows-style filename.
philpem@5 5065 inline void winformat_string(char *const s) {
philpem@5 5066 if (s && s[0]) {
philpem@5 5067 #if cimg_OS==2
philpem@5 5068 char *const ns = new char[MAX_PATH];
philpem@5 5069 if (GetShortPathNameA(s,ns,MAX_PATH)) cimg_std::strcpy(s,ns);
philpem@5 5070 #endif
philpem@5 5071 }
philpem@5 5072 }
philpem@5 5073
philpem@5 5074 //! Return or set path to store temporary files.
philpem@5 5075 inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5076 #define _cimg_test_temporary_path(p) \
philpem@5 5077 if (!path_found) { \
philpem@5 5078 cimg_std::sprintf(st_path,"%s",p); \
philpem@5 5079 cimg_std::sprintf(tmp,"%s%s%s",st_path,cimg_OS==2?"\\":"/",filetmp); \
philpem@5 5080 if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; } \
philpem@5 5081 }
philpem@5 5082 static char *st_path = 0;
philpem@5 5083 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5084 if (user_path) {
philpem@5 5085 if (!st_path) st_path = new char[1024];
philpem@5 5086 cimg_std::memset(st_path,0,1024);
philpem@5 5087 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5088 } else if (!st_path) {
philpem@5 5089 st_path = new char[1024];
philpem@5 5090 cimg_std::memset(st_path,0,1024);
philpem@5 5091 bool path_found = false;
philpem@5 5092 char tmp[1024], filetmp[512];
philpem@5 5093 cimg_std::FILE *file = 0;
philpem@5 5094 cimg_std::sprintf(filetmp,"%s.tmp",cimg::filenamerand());
philpem@5 5095 char *tmpPath = getenv("TMP");
philpem@5 5096 if (!tmpPath) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); }
philpem@5 5097 if (tmpPath) _cimg_test_temporary_path(tmpPath);
philpem@5 5098 #if cimg_OS==2
philpem@5 5099 _cimg_test_temporary_path("C:\\WINNT\\Temp");
philpem@5 5100 _cimg_test_temporary_path("C:\\WINDOWS\\Temp");
philpem@5 5101 _cimg_test_temporary_path("C:\\Temp");
philpem@5 5102 _cimg_test_temporary_path("C:");
philpem@5 5103 _cimg_test_temporary_path("D:\\WINNT\\Temp");
philpem@5 5104 _cimg_test_temporary_path("D:\\WINDOWS\\Temp");
philpem@5 5105 _cimg_test_temporary_path("D:\\Temp");
philpem@5 5106 _cimg_test_temporary_path("D:");
philpem@5 5107 #else
philpem@5 5108 _cimg_test_temporary_path("/tmp");
philpem@5 5109 _cimg_test_temporary_path("/var/tmp");
philpem@5 5110 #endif
philpem@5 5111 if (!path_found) {
philpem@5 5112 st_path[0]='\0';
philpem@5 5113 cimg_std::strcpy(tmp,filetmp);
philpem@5 5114 if ((file=cimg_std::fopen(tmp,"wb"))!=0) { cimg_std::fclose(file); cimg_std::remove(tmp); path_found = true; }
philpem@5 5115 }
philpem@5 5116 if (!path_found)
philpem@5 5117 throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n"
philpem@5 5118 "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n"
philpem@5 5119 "#define cimg_temporary_path \"path\" (before including 'CImg.h')");
philpem@5 5120 }
philpem@5 5121 return st_path;
philpem@5 5122 }
philpem@5 5123
philpem@5 5124 // Return or set path to the "Program files/" directory (windows only).
philpem@5 5125 #if cimg_OS==2
philpem@5 5126 inline const char* programfiles_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5127 static char *st_path = 0;
philpem@5 5128 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5129 if (user_path) {
philpem@5 5130 if (!st_path) st_path = new char[1024];
philpem@5 5131 cimg_std::memset(st_path,0,1024);
philpem@5 5132 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5133 } else if (!st_path) {
philpem@5 5134 st_path = new char[MAX_PATH];
philpem@5 5135 cimg_std::memset(st_path,0,MAX_PATH);
philpem@5 5136 // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler).
philpem@5 5137 #if !defined(__INTEL_COMPILER)
philpem@5 5138 if (!SHGetSpecialFolderPathA(0,st_path,0x0026,false)) {
philpem@5 5139 const char *pfPath = getenv("PROGRAMFILES");
philpem@5 5140 if (pfPath) cimg_std::strncpy(st_path,pfPath,MAX_PATH-1);
philpem@5 5141 else cimg_std::strcpy(st_path,"C:\\PROGRA~1");
philpem@5 5142 }
philpem@5 5143 #else
philpem@5 5144 cimg_std::strcpy(st_path,"C:\\PROGRA~1");
philpem@5 5145 #endif
philpem@5 5146 }
philpem@5 5147 return st_path;
philpem@5 5148 }
philpem@5 5149 #endif
philpem@5 5150
philpem@5 5151 //! Return or set path to the ImageMagick's \c convert tool.
philpem@5 5152 inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5153 static char *st_path = 0;
philpem@5 5154 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5155 if (user_path) {
philpem@5 5156 if (!st_path) st_path = new char[1024];
philpem@5 5157 cimg_std::memset(st_path,0,1024);
philpem@5 5158 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5159 } else if (!st_path) {
philpem@5 5160 st_path = new char[1024];
philpem@5 5161 cimg_std::memset(st_path,0,1024);
philpem@5 5162 bool path_found = false;
philpem@5 5163 cimg_std::FILE *file = 0;
philpem@5 5164 #if cimg_OS==2
philpem@5 5165 const char *pf_path = programfiles_path();
philpem@5 5166 if (!path_found) {
philpem@5 5167 cimg_std::sprintf(st_path,".\\convert.exe");
philpem@5 5168 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5169 }
philpem@5 5170 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5171 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\convert.exe",pf_path,k);
philpem@5 5172 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5173 }}
philpem@5 5174 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5175 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\convert.exe",pf_path,k);
philpem@5 5176 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5177 }}
philpem@5 5178 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5179 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\convert.exe",pf_path,k);
philpem@5 5180 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5181 }}
philpem@5 5182 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5183 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",pf_path,k);
philpem@5 5184 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5185 }}
philpem@5 5186 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5187 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k);
philpem@5 5188 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5189 }}
philpem@5 5190 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5191 cimg_std::sprintf(st_path,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",pf_path,k);
philpem@5 5192 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5193 }}
philpem@5 5194 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5195 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\convert.exe",k);
philpem@5 5196 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5197 }}
philpem@5 5198 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5199 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\convert.exe",k);
philpem@5 5200 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5201 }}
philpem@5 5202 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5203 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\convert.exe",k);
philpem@5 5204 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5205 }}
philpem@5 5206 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5207 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5208 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5209 }}
philpem@5 5210 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5211 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5212 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5213 }}
philpem@5 5214 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5215 cimg_std::sprintf(st_path,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5216 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5217 }}
philpem@5 5218 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5219 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\convert.exe",k);
philpem@5 5220 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5221 }}
philpem@5 5222 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5223 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\convert.exe",k);
philpem@5 5224 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5225 }}
philpem@5 5226 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5227 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\convert.exe",k);
philpem@5 5228 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5229 }}
philpem@5 5230 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5231 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5232 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5233 }}
philpem@5 5234 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5235 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5236 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5237 }}
philpem@5 5238 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5239 cimg_std::sprintf(st_path,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\convert.exe",k);
philpem@5 5240 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5241 }}
philpem@5 5242 if (!path_found) cimg_std::strcpy(st_path,"convert.exe");
philpem@5 5243 #else
philpem@5 5244 if (!path_found) {
philpem@5 5245 cimg_std::sprintf(st_path,"./convert");
philpem@5 5246 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5247 }
philpem@5 5248 if (!path_found) cimg_std::strcpy(st_path,"convert");
philpem@5 5249 #endif
philpem@5 5250 winformat_string(st_path);
philpem@5 5251 }
philpem@5 5252 return st_path;
philpem@5 5253 }
philpem@5 5254
philpem@5 5255 //! Return path of the GraphicsMagick's \c gm tool.
philpem@5 5256 inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5257 static char *st_path = 0;
philpem@5 5258 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5259 if (user_path) {
philpem@5 5260 if (!st_path) st_path = new char[1024];
philpem@5 5261 cimg_std::memset(st_path,0,1024);
philpem@5 5262 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5263 } else if (!st_path) {
philpem@5 5264 st_path = new char[1024];
philpem@5 5265 cimg_std::memset(st_path,0,1024);
philpem@5 5266 bool path_found = false;
philpem@5 5267 cimg_std::FILE *file = 0;
philpem@5 5268 #if cimg_OS==2
philpem@5 5269 const char* pf_path = programfiles_path();
philpem@5 5270 if (!path_found) {
philpem@5 5271 cimg_std::sprintf(st_path,".\\gm.exe");
philpem@5 5272 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5273 }
philpem@5 5274 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5275 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k);
philpem@5 5276 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5277 }}
philpem@5 5278 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5279 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k);
philpem@5 5280 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5281 }}
philpem@5 5282 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5283 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k);
philpem@5 5284 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5285 }}
philpem@5 5286 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5287 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k);
philpem@5 5288 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5289 }}
philpem@5 5290 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5291 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k);
philpem@5 5292 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5293 }}
philpem@5 5294 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5295 cimg_std::sprintf(st_path,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k);
philpem@5 5296 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5297 }}
philpem@5 5298 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5299 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\gm.exe",k);
philpem@5 5300 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5301 }}
philpem@5 5302 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5303 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\gm.exe",k);
philpem@5 5304 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5305 }}
philpem@5 5306 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5307 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\gm.exe",k);
philpem@5 5308 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5309 }}
philpem@5 5310 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5311 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5312 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5313 }}
philpem@5 5314 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5315 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5316 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5317 }}
philpem@5 5318 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5319 cimg_std::sprintf(st_path,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5320 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5321 }}
philpem@5 5322 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5323 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\gm.exe",k);
philpem@5 5324 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5325 }}
philpem@5 5326 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5327 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\gm.exe",k);
philpem@5 5328 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5329 }}
philpem@5 5330 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5331 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\gm.exe",k);
philpem@5 5332 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5333 }}
philpem@5 5334 { for (int k=32; k>=10 && !path_found; --k) {
philpem@5 5335 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5336 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5337 }}
philpem@5 5338 { for (int k=9; k>=0 && !path_found; --k) {
philpem@5 5339 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5340 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5341 }}
philpem@5 5342 { for (int k=32; k>=0 && !path_found; --k) {
philpem@5 5343 cimg_std::sprintf(st_path,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k);
philpem@5 5344 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5345 }}
philpem@5 5346 if (!path_found) cimg_std::strcpy(st_path,"gm.exe");
philpem@5 5347 #else
philpem@5 5348 if (!path_found) {
philpem@5 5349 cimg_std::sprintf(st_path,"./gm");
philpem@5 5350 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5351 }
philpem@5 5352 if (!path_found) cimg_std::strcpy(st_path,"gm");
philpem@5 5353 #endif
philpem@5 5354 winformat_string(st_path);
philpem@5 5355 }
philpem@5 5356 return st_path;
philpem@5 5357 }
philpem@5 5358
philpem@5 5359 //! Return or set path of the \c XMedcon tool.
philpem@5 5360 inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5361 static char *st_path = 0;
philpem@5 5362 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5363 if (user_path) {
philpem@5 5364 if (!st_path) st_path = new char[1024];
philpem@5 5365 cimg_std::memset(st_path,0,1024);
philpem@5 5366 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5367 } else if (!st_path) {
philpem@5 5368 st_path = new char[1024];
philpem@5 5369 cimg_std::memset(st_path,0,1024);
philpem@5 5370 bool path_found = false;
philpem@5 5371 cimg_std::FILE *file = 0;
philpem@5 5372 #if cimg_OS==2
philpem@5 5373 const char* pf_path = programfiles_path();
philpem@5 5374 if (!path_found) {
philpem@5 5375 cimg_std::sprintf(st_path,".\\medcon.bat");
philpem@5 5376 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5377 }
philpem@5 5378 if (!path_found) {
philpem@5 5379 cimg_std::sprintf(st_path,".\\medcon.exe");
philpem@5 5380 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5381 }
philpem@5 5382 if (!path_found) {
philpem@5 5383 cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path);
philpem@5 5384 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5385 }
philpem@5 5386 if (!path_found) {
philpem@5 5387 cimg_std::sprintf(st_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path);
philpem@5 5388 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5389 }
philpem@5 5390 if (!path_found) cimg_std::strcpy(st_path,"medcon.bat");
philpem@5 5391 #else
philpem@5 5392 if (!path_found) {
philpem@5 5393 cimg_std::sprintf(st_path,"./medcon");
philpem@5 5394 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5395 }
philpem@5 5396 if (!path_found) cimg_std::strcpy(st_path,"medcon");
philpem@5 5397 #endif
philpem@5 5398 winformat_string(st_path);
philpem@5 5399 }
philpem@5 5400 return st_path;
philpem@5 5401 }
philpem@5 5402
philpem@5 5403 //! Return or set path to the 'ffmpeg' command.
philpem@5 5404 inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5405 static char *st_path = 0;
philpem@5 5406 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5407 if (user_path) {
philpem@5 5408 if (!st_path) st_path = new char[1024];
philpem@5 5409 cimg_std::memset(st_path,0,1024);
philpem@5 5410 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5411 } else if (!st_path) {
philpem@5 5412 st_path = new char[1024];
philpem@5 5413 cimg_std::memset(st_path,0,1024);
philpem@5 5414 bool path_found = false;
philpem@5 5415 cimg_std::FILE *file = 0;
philpem@5 5416 #if cimg_OS==2
philpem@5 5417 if (!path_found) {
philpem@5 5418 cimg_std::sprintf(st_path,".\\ffmpeg.exe");
philpem@5 5419 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5420 }
philpem@5 5421 if (!path_found) cimg_std::strcpy(st_path,"ffmpeg.exe");
philpem@5 5422 #else
philpem@5 5423 if (!path_found) {
philpem@5 5424 cimg_std::sprintf(st_path,"./ffmpeg");
philpem@5 5425 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5426 }
philpem@5 5427 if (!path_found) cimg_std::strcpy(st_path,"ffmpeg");
philpem@5 5428 #endif
philpem@5 5429 winformat_string(st_path);
philpem@5 5430 }
philpem@5 5431 return st_path;
philpem@5 5432 }
philpem@5 5433
philpem@5 5434 //! Return or set path to the 'gzip' command.
philpem@5 5435 inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5436 static char *st_path = 0;
philpem@5 5437 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5438 if (user_path) {
philpem@5 5439 if (!st_path) st_path = new char[1024];
philpem@5 5440 cimg_std::memset(st_path,0,1024);
philpem@5 5441 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5442 } else if (!st_path) {
philpem@5 5443 st_path = new char[1024];
philpem@5 5444 cimg_std::memset(st_path,0,1024);
philpem@5 5445 bool path_found = false;
philpem@5 5446 cimg_std::FILE *file = 0;
philpem@5 5447 #if cimg_OS==2
philpem@5 5448 if (!path_found) {
philpem@5 5449 cimg_std::sprintf(st_path,".\\gzip.exe");
philpem@5 5450 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5451 }
philpem@5 5452 if (!path_found) cimg_std::strcpy(st_path,"gzip.exe");
philpem@5 5453 #else
philpem@5 5454 if (!path_found) {
philpem@5 5455 cimg_std::sprintf(st_path,"./gzip");
philpem@5 5456 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5457 }
philpem@5 5458 if (!path_found) cimg_std::strcpy(st_path,"gzip");
philpem@5 5459 #endif
philpem@5 5460 winformat_string(st_path);
philpem@5 5461 }
philpem@5 5462 return st_path;
philpem@5 5463 }
philpem@5 5464
philpem@5 5465 //! Return or set path to the 'gunzip' command.
philpem@5 5466 inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5467 static char *st_path = 0;
philpem@5 5468 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5469 if (user_path) {
philpem@5 5470 if (!st_path) st_path = new char[1024];
philpem@5 5471 cimg_std::memset(st_path,0,1024);
philpem@5 5472 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5473 } else if (!st_path) {
philpem@5 5474 st_path = new char[1024];
philpem@5 5475 cimg_std::memset(st_path,0,1024);
philpem@5 5476 bool path_found = false;
philpem@5 5477 cimg_std::FILE *file = 0;
philpem@5 5478 #if cimg_OS==2
philpem@5 5479 if (!path_found) {
philpem@5 5480 cimg_std::sprintf(st_path,".\\gunzip.exe");
philpem@5 5481 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5482 }
philpem@5 5483 if (!path_found) cimg_std::strcpy(st_path,"gunzip.exe");
philpem@5 5484 #else
philpem@5 5485 if (!path_found) {
philpem@5 5486 cimg_std::sprintf(st_path,"./gunzip");
philpem@5 5487 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5488 }
philpem@5 5489 if (!path_found) cimg_std::strcpy(st_path,"gunzip");
philpem@5 5490 #endif
philpem@5 5491 winformat_string(st_path);
philpem@5 5492 }
philpem@5 5493 return st_path;
philpem@5 5494 }
philpem@5 5495
philpem@5 5496 //! Return or set path to the 'dcraw' command.
philpem@5 5497 inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false) {
philpem@5 5498 static char *st_path = 0;
philpem@5 5499 if (reinit_path && st_path) { delete[] st_path; st_path = 0; }
philpem@5 5500 if (user_path) {
philpem@5 5501 if (!st_path) st_path = new char[1024];
philpem@5 5502 cimg_std::memset(st_path,0,1024);
philpem@5 5503 cimg_std::strncpy(st_path,user_path,1023);
philpem@5 5504 } else if (!st_path) {
philpem@5 5505 st_path = new char[1024];
philpem@5 5506 cimg_std::memset(st_path,0,1024);
philpem@5 5507 bool path_found = false;
philpem@5 5508 cimg_std::FILE *file = 0;
philpem@5 5509 #if cimg_OS==2
philpem@5 5510 if (!path_found) {
philpem@5 5511 cimg_std::sprintf(st_path,".\\dcraw.exe");
philpem@5 5512 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5513 }
philpem@5 5514 if (!path_found) cimg_std::strcpy(st_path,"dcraw.exe");
philpem@5 5515 #else
philpem@5 5516 if (!path_found) {
philpem@5 5517 cimg_std::sprintf(st_path,"./dcraw");
philpem@5 5518 if ((file=cimg_std::fopen(st_path,"r"))!=0) { cimg_std::fclose(file); path_found = true; }
philpem@5 5519 }
philpem@5 5520 if (!path_found) cimg_std::strcpy(st_path,"dcraw");
philpem@5 5521 #endif
philpem@5 5522 winformat_string(st_path);
philpem@5 5523 }
philpem@5 5524 return st_path;
philpem@5 5525 }
philpem@5 5526
philpem@5 5527 //! Split a filename into two strings 'body' and 'extension'.
philpem@5 5528 inline const char *split_filename(const char *const filename, char *const body=0) {
philpem@5 5529 if (!filename) { if (body) body[0]='\0'; return 0; }
philpem@5 5530 int l = cimg::strfind(filename,'.');
philpem@5 5531 if (l>=0) { if (body) { cimg_std::strncpy(body,filename,l); body[l]='\0'; }}
philpem@5 5532 else { if (body) cimg_std::strcpy(body,filename); l = (int)cimg::strlen(filename)-1; }
philpem@5 5533 return filename+l+1;
philpem@5 5534 }
philpem@5 5535
philpem@5 5536 //! Create a numbered version of a filename.
philpem@5 5537 inline char* number_filename(const char *const filename, const int number, const unsigned int n, char *const string) {
philpem@5 5538 if (!filename) { if (string) string[0]='\0'; return 0; }
philpem@5 5539 char format[1024],body[1024];
philpem@5 5540 const char *ext = cimg::split_filename(filename,body);
philpem@5 5541 if (n>0) cimg_std::sprintf(format,"%s_%%.%ud.%s",body,n,ext);
philpem@5 5542 else cimg_std::sprintf(format,"%s_%%d.%s",body,ext);
philpem@5 5543 cimg_std::sprintf(string,format,number);
philpem@5 5544 return string;
philpem@5 5545 }
philpem@5 5546
philpem@5 5547 //! Open a file, and check for possible errors.
philpem@5 5548 inline cimg_std::FILE *fopen(const char *const path, const char *const mode) {
philpem@5 5549 if(!path || !mode)
philpem@5 5550 throw CImgArgumentException("cimg::fopen() : File '%s', cannot open with mode '%s'.",
philpem@5 5551 path?path:"(null)",mode?mode:"(null)");
philpem@5 5552 if (path[0]=='-') return (mode[0]=='r')?stdin:stdout;
philpem@5 5553 cimg_std::FILE *dest = cimg_std::fopen(path,mode);
philpem@5 5554 if (!dest)
philpem@5 5555 throw CImgIOException("cimg::fopen() : File '%s', cannot open file %s",
philpem@5 5556 path,mode[0]=='r'?"for reading.":(mode[0]=='w'?"for writing.":"."),path);
philpem@5 5557 return dest;
philpem@5 5558 }
philpem@5 5559
philpem@5 5560 //! Close a file, and check for possible errors.
philpem@5 5561 inline int fclose(cimg_std::FILE *file) {
philpem@5 5562 if (!file) warn("cimg::fclose() : Can't close (null) file");
philpem@5 5563 if (!file || file==stdin || file==stdout) return 0;
philpem@5 5564 const int errn = cimg_std::fclose(file);
philpem@5 5565 if (errn!=0) warn("cimg::fclose() : Error %d during file closing",errn);
philpem@5 5566 return errn;
philpem@5 5567 }
philpem@5 5568
philpem@5 5569 //! Try to guess the image format of a filename, using its magick numbers.
philpem@5 5570 inline const char *file_type(cimg_std::FILE *const file, const char *const filename) {
philpem@5 5571 static const char
philpem@5 5572 *const _pnm = "pnm",
philpem@5 5573 *const _bmp = "bmp",
philpem@5 5574 *const _gif = "gif",
philpem@5 5575 *const _jpeg = "jpeg",
philpem@5 5576 *const _off = "off",
philpem@5 5577 *const _pan = "pan",
philpem@5 5578 *const _png = "png",
philpem@5 5579 *const _tiff = "tiff";
philpem@5 5580 if (!filename && !file) throw CImgArgumentException("cimg::file_type() : Cannot load (null) filename.");
philpem@5 5581 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 5582 const char *ftype = 0, *head;
philpem@5 5583 char header[2048], item[1024];
philpem@5 5584 const unsigned char *const uheader = (unsigned char*)header;
philpem@5 5585 int err;
philpem@5 5586 const unsigned int siz = (unsigned int)cimg_std::fread(header,2048,1,nfile); // Read first 2048 bytes.
philpem@5 5587 if (!file) cimg::fclose(nfile);
philpem@5 5588 if (!ftype) { // Check for BMP format.
philpem@5 5589 if (header[0]=='B' && header[1]=='M') ftype = _bmp;
philpem@5 5590 }
philpem@5 5591 if (!ftype) { // Check for GIF format.
philpem@5 5592 if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' &&
philpem@5 5593 (header[4]=='7' || header[4]=='9')) ftype = _gif;
philpem@5 5594 }
philpem@5 5595 if (!ftype) { // Check for JPEG format.
philpem@5 5596 if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) ftype = _jpeg;
philpem@5 5597 }
philpem@5 5598 if (!ftype) { // Check for OFF format.
philpem@5 5599 if (header[0]=='O' && header[1]=='F' && header[2]=='F' && header[3]=='\n') ftype = _off;
philpem@5 5600 }
philpem@5 5601 if (!ftype) { // Check for PAN format.
philpem@5 5602 if (header[0]=='P' && header[1]=='A' && header[2]=='N' && header[3]=='D' && header[4]=='O' &&
philpem@5 5603 header[5]=='R' && header[6]=='E') ftype = _pan;
philpem@5 5604 }
philpem@5 5605 if (!ftype) { // Check for PNG format.
philpem@5 5606 if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 &&
philpem@5 5607 uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) ftype = _png;
philpem@5 5608 }
philpem@5 5609 if (!ftype) { // Check for PNM format.
philpem@5 5610 head = header;
philpem@5 5611 while (head<header+siz && (err=cimg_std::sscanf(head,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err))
philpem@5 5612 head+=1+(err?cimg::strlen(item):0);
philpem@5 5613 if (cimg_std::sscanf(item," P%d",&err)==1) ftype = _pnm;
philpem@5 5614 }
philpem@5 5615 if (!ftype) { // Check for TIFF format.
philpem@5 5616 if ((uheader[0]==0x49 && uheader[1]==0x49) || (uheader[0]==0x4D && uheader[1]==0x4D)) ftype = _tiff;
philpem@5 5617 }
philpem@5 5618 return ftype;
philpem@5 5619 }
philpem@5 5620
philpem@5 5621 //! Read file data, and check for possible errors.
philpem@5 5622 template<typename T>
philpem@5 5623 inline int fread(T *const ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
philpem@5 5624 if (!ptr || nmemb<=0 || !stream)
philpem@5 5625 throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'",
philpem@5 5626 nmemb,sizeof(T),stream,ptr);
philpem@5 5627 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
philpem@5 5628 unsigned int toread = nmemb, alread = 0, ltoread = 0, lalread = 0;
philpem@5 5629 do {
philpem@5 5630 ltoread = (toread*sizeof(T))<wlimitT?toread:wlimit;
philpem@5 5631 lalread = (unsigned int)cimg_std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream);
philpem@5 5632 alread+=lalread;
philpem@5 5633 toread-=lalread;
philpem@5 5634 } while (ltoread==lalread && toread>0);
philpem@5 5635 if (toread>0) warn("cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb);
philpem@5 5636 return alread;
philpem@5 5637 }
philpem@5 5638
philpem@5 5639 //! Write data to a file, and check for possible errors.
philpem@5 5640 template<typename T>
philpem@5 5641 inline int fwrite(const T *ptr, const unsigned int nmemb, cimg_std::FILE *stream) {
philpem@5 5642 if (!ptr || !stream)
philpem@5 5643 throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'",
philpem@5 5644 nmemb,sizeof(T),stream,ptr);
philpem@5 5645 if (nmemb<=0) return 0;
philpem@5 5646 const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T);
philpem@5 5647 unsigned int towrite = nmemb, alwrite = 0, ltowrite = 0, lalwrite = 0;
philpem@5 5648 do {
philpem@5 5649 ltowrite = (towrite*sizeof(T))<wlimitT?towrite:wlimit;
philpem@5 5650 lalwrite = (unsigned int)cimg_std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream);
philpem@5 5651 alwrite+=lalwrite;
philpem@5 5652 towrite-=lalwrite;
philpem@5 5653 } while (ltowrite==lalwrite && towrite>0);
philpem@5 5654 if (towrite>0) warn("cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb);
philpem@5 5655 return alwrite;
philpem@5 5656 }
philpem@5 5657
philpem@5 5658 inline const char* option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5659 const char *defaut, const char *const usage=0) {
philpem@5 5660 static bool first = true, visu = false;
philpem@5 5661 const char *res = 0;
philpem@5 5662 if (first) {
philpem@5 5663 first=false;
philpem@5 5664 visu = (cimg::option("-h",argc,argv,(char*)0)!=0);
philpem@5 5665 visu |= (cimg::option("-help",argc,argv,(char*)0)!=0);
philpem@5 5666 visu |= (cimg::option("--help",argc,argv,(char*)0)!=0);
philpem@5 5667 }
philpem@5 5668 if (!name && visu) {
philpem@5 5669 if (usage) {
philpem@5 5670 cimg_std::fprintf(cimg_stdout,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal);
philpem@5 5671 cimg_std::fprintf(cimg_stdout," : %s",usage);
philpem@5 5672 cimg_std::fprintf(cimg_stdout," (%s, %s)\n\n",__DATE__,__TIME__);
philpem@5 5673 }
philpem@5 5674 if (defaut) cimg_std::fprintf(cimg_stdout,"%s\n",defaut);
philpem@5 5675 }
philpem@5 5676 if (name) {
philpem@5 5677 if (argc>0) {
philpem@5 5678 int k = 0;
philpem@5 5679 while (k<argc && cimg::strcmp(argv[k],name)) ++k;
philpem@5 5680 res = (k++==argc?defaut:(k==argc?argv[--k]:argv[k]));
philpem@5 5681 } else res = defaut;
philpem@5 5682 if (visu && usage) cimg_std::fprintf(cimg_stdout," %s%-16s%s %-24s %s%s%s\n",
philpem@5 5683 cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_green,usage,cimg::t_normal);
philpem@5 5684 }
philpem@5 5685 return res;
philpem@5 5686 }
philpem@5 5687
philpem@5 5688 inline bool option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5689 const bool defaut, const char *const usage=0) {
philpem@5 5690 const char *s = cimg::option(name,argc,argv,(char*)0);
philpem@5 5691 const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut;
philpem@5 5692 cimg::option(name,0,0,res?"true":"false",usage);
philpem@5 5693 return res;
philpem@5 5694 }
philpem@5 5695
philpem@5 5696 inline int option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5697 const int defaut, const char *const usage=0) {
philpem@5 5698 const char *s = cimg::option(name,argc,argv,(char*)0);
philpem@5 5699 const int res = s?cimg_std::atoi(s):defaut;
philpem@5 5700 char tmp[256];
philpem@5 5701 cimg_std::sprintf(tmp,"%d",res);
philpem@5 5702 cimg::option(name,0,0,tmp,usage);
philpem@5 5703 return res;
philpem@5 5704 }
philpem@5 5705
philpem@5 5706 inline char option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5707 const char defaut, const char *const usage=0) {
philpem@5 5708 const char *s = cimg::option(name,argc,argv,(char*)0);
philpem@5 5709 const char res = s?s[0]:defaut;
philpem@5 5710 char tmp[8];
philpem@5 5711 tmp[0] = res; tmp[1] ='\0';
philpem@5 5712 cimg::option(name,0,0,tmp,usage);
philpem@5 5713 return res;
philpem@5 5714 }
philpem@5 5715
philpem@5 5716 inline float option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5717 const float defaut, const char *const usage=0) {
philpem@5 5718 const char *s = cimg::option(name,argc,argv,(char*)0);
philpem@5 5719 const float res = s?cimg::atof(s):defaut;
philpem@5 5720 char tmp[256];
philpem@5 5721 cimg_std::sprintf(tmp,"%g",res);
philpem@5 5722 cimg::option(name,0,0,tmp,usage);
philpem@5 5723 return res;
philpem@5 5724 }
philpem@5 5725
philpem@5 5726 inline double option(const char *const name, const int argc, const char *const *const argv,
philpem@5 5727 const double defaut, const char *const usage=0) {
philpem@5 5728 const char *s = cimg::option(name,argc,argv,(char*)0);
philpem@5 5729 const double res = s?cimg::atof(s):defaut;
philpem@5 5730 char tmp[256];
philpem@5 5731 cimg_std::sprintf(tmp,"%g",res);
philpem@5 5732 cimg::option(name,0,0,tmp,usage);
philpem@5 5733 return res;
philpem@5 5734 }
philpem@5 5735
philpem@5 5736 inline const char* argument(const unsigned int nb, const int argc, const char *const *const argv, const unsigned int nb_singles=0, ...) {
philpem@5 5737 for (int k = 1, pos = 0; k<argc;) {
philpem@5 5738 const char *const item = argv[k];
philpem@5 5739 bool option = (*item=='-'), single_option = false;
philpem@5 5740 if (option) {
philpem@5 5741 va_list ap;
philpem@5 5742 va_start(ap,nb_singles);
philpem@5 5743 for (unsigned int i=0; i<nb_singles; ++i) if (!cimg::strcasecmp(item,va_arg(ap,char*))) { single_option = true; break; }
philpem@5 5744 va_end(ap);
philpem@5 5745 }
philpem@5 5746 if (option) { ++k; if (!single_option) ++k; }
philpem@5 5747 else { if (pos++==(int)nb) return item; else ++k; }
philpem@5 5748 }
philpem@5 5749 return 0;
philpem@5 5750 }
philpem@5 5751
philpem@5 5752 //! Print informations about %CImg environement variables.
philpem@5 5753 /**
philpem@5 5754 Printing is done on the standard error output.
philpem@5 5755 **/
philpem@5 5756 inline void info() {
philpem@5 5757 char tmp[1024] = { 0 };
philpem@5 5758 cimg_std::fprintf(cimg_stdout,"\n %sCImg Library %u.%u.%u%s, compiled %s ( %s ) with the following flags :\n\n",
philpem@5 5759 cimg::t_red,cimg_version/100,(cimg_version/10)%10,cimg_version%10,
philpem@5 5760 cimg::t_normal,__DATE__,__TIME__);
philpem@5 5761
philpem@5 5762 cimg_std::fprintf(cimg_stdout," > Operating System : %s%-13s%s %s('cimg_OS'=%d)%s\n",
philpem@5 5763 cimg::t_bold,
philpem@5 5764 cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"),
philpem@5 5765 cimg::t_normal,cimg::t_green,
philpem@5 5766 cimg_OS,
philpem@5 5767 cimg::t_normal);
philpem@5 5768
philpem@5 5769 cimg_std::fprintf(cimg_stdout," > CPU endianness : %s%s Endian%s\n",
philpem@5 5770 cimg::t_bold,
philpem@5 5771 cimg::endianness()?"Big":"Little",
philpem@5 5772 cimg::t_normal);
philpem@5 5773
philpem@5 5774 #ifdef cimg_use_visualcpp6
philpem@5 5775 cimg_std::fprintf(cimg_stdout," > Using Visual C++ 6.0 : %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n",
philpem@5 5776 cimg::t_bold,"Yes",cimg::t_normal,cimg::t_green,cimg::t_normal);
philpem@5 5777 #endif
philpem@5 5778
philpem@5 5779 cimg_std::fprintf(cimg_stdout," > Debug messages : %s%-13s%s %s('cimg_debug'=%d)%s\n",
philpem@5 5780 cimg::t_bold,
philpem@5 5781 cimg_debug==0?"Quiet":(cimg_debug==1?"Console":(cimg_debug==2?"Dialog":(cimg_debug==3?"Console+Warnings":"Dialog+Warnings"))),
philpem@5 5782 cimg::t_normal,cimg::t_green,
philpem@5 5783 cimg_debug,
philpem@5 5784 cimg::t_normal);
philpem@5 5785
philpem@5 5786 cimg_std::fprintf(cimg_stdout," > Stricts warnings : %s%-13s%s %s('cimg_strict_warnings' %s)%s\n",
philpem@5 5787 cimg::t_bold,
philpem@5 5788 #ifdef cimg_strict_warnings
philpem@5 5789 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5790 #else
philpem@5 5791 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5792 #endif
philpem@5 5793 cimg::t_normal);
philpem@5 5794
philpem@5 5795 cimg_std::fprintf(cimg_stdout," > Using VT100 messages : %s%-13s%s %s('cimg_use_vt100' %s)%s\n",
philpem@5 5796 cimg::t_bold,
philpem@5 5797 #ifdef cimg_use_vt100
philpem@5 5798 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5799 #else
philpem@5 5800 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5801 #endif
philpem@5 5802 cimg::t_normal);
philpem@5 5803
philpem@5 5804 cimg_std::fprintf(cimg_stdout," > Display type : %s%-13s%s %s('cimg_display'=%d)%s\n",
philpem@5 5805 cimg::t_bold,
philpem@5 5806 cimg_display==0?"No display":
philpem@5 5807 (cimg_display==1?"X11":
philpem@5 5808 (cimg_display==2?"Windows GDI":
philpem@5 5809 (cimg_display==3?"Carbon":"Unknow"))),
philpem@5 5810 cimg::t_normal,cimg::t_green,
philpem@5 5811 cimg_display,
philpem@5 5812 cimg::t_normal);
philpem@5 5813
philpem@5 5814 #if cimg_display==1
philpem@5 5815 cimg_std::fprintf(cimg_stdout," > Using XShm for X11 : %s%-13s%s %s('cimg_use_xshm' %s)%s\n",
philpem@5 5816 cimg::t_bold,
philpem@5 5817 #ifdef cimg_use_xshm
philpem@5 5818 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5819 #else
philpem@5 5820 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5821 #endif
philpem@5 5822 cimg::t_normal);
philpem@5 5823
philpem@5 5824 cimg_std::fprintf(cimg_stdout," > Using XRand for X11 : %s%-13s%s %s('cimg_use_xrandr' %s)%s\n",
philpem@5 5825 cimg::t_bold,
philpem@5 5826 #ifdef cimg_use_xrandr
philpem@5 5827 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5828 #else
philpem@5 5829 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5830 #endif
philpem@5 5831 cimg::t_normal);
philpem@5 5832 #endif
philpem@5 5833 cimg_std::fprintf(cimg_stdout," > Using OpenMP : %s%-13s%s %s('cimg_use_openmp' %s)%s\n",
philpem@5 5834 cimg::t_bold,
philpem@5 5835 #ifdef cimg_use_openmp
philpem@5 5836 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5837 #else
philpem@5 5838 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5839 #endif
philpem@5 5840 cimg::t_normal);
philpem@5 5841 cimg_std::fprintf(cimg_stdout," > Using PNG library : %s%-13s%s %s('cimg_use_png' %s)%s\n",
philpem@5 5842 cimg::t_bold,
philpem@5 5843 #ifdef cimg_use_png
philpem@5 5844 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5845 #else
philpem@5 5846 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5847 #endif
philpem@5 5848 cimg::t_normal);
philpem@5 5849 cimg_std::fprintf(cimg_stdout," > Using JPEG library : %s%-13s%s %s('cimg_use_jpeg' %s)%s\n",
philpem@5 5850 cimg::t_bold,
philpem@5 5851 #ifdef cimg_use_jpeg
philpem@5 5852 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5853 #else
philpem@5 5854 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5855 #endif
philpem@5 5856 cimg::t_normal);
philpem@5 5857
philpem@5 5858 cimg_std::fprintf(cimg_stdout," > Using TIFF library : %s%-13s%s %s('cimg_use_tiff' %s)%s\n",
philpem@5 5859 cimg::t_bold,
philpem@5 5860 #ifdef cimg_use_tiff
philpem@5 5861 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5862 #else
philpem@5 5863 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5864 #endif
philpem@5 5865 cimg::t_normal);
philpem@5 5866
philpem@5 5867 cimg_std::fprintf(cimg_stdout," > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n",
philpem@5 5868 cimg::t_bold,
philpem@5 5869 #ifdef cimg_use_magick
philpem@5 5870 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5871 #else
philpem@5 5872 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5873 #endif
philpem@5 5874 cimg::t_normal);
philpem@5 5875
philpem@5 5876 cimg_std::fprintf(cimg_stdout," > Using FFTW3 library : %s%-13s%s %s('cimg_use_fftw3' %s)%s\n",
philpem@5 5877 cimg::t_bold,
philpem@5 5878 #ifdef cimg_use_fftw3
philpem@5 5879 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5880 #else
philpem@5 5881 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5882 #endif
philpem@5 5883 cimg::t_normal);
philpem@5 5884
philpem@5 5885 cimg_std::fprintf(cimg_stdout," > Using LAPACK library : %s%-13s%s %s('cimg_use_lapack' %s)%s\n",
philpem@5 5886 cimg::t_bold,
philpem@5 5887 #ifdef cimg_use_lapack
philpem@5 5888 "Yes",cimg::t_normal,cimg::t_green,"defined",
philpem@5 5889 #else
philpem@5 5890 "No",cimg::t_normal,cimg::t_green,"undefined",
philpem@5 5891 #endif
philpem@5 5892 cimg::t_normal);
philpem@5 5893
philpem@5 5894 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path());
philpem@5 5895 cimg_std::fprintf(cimg_stdout," > Path of ImageMagick : %s%-13s%s\n",
philpem@5 5896 cimg::t_bold,
philpem@5 5897 tmp,
philpem@5 5898 cimg::t_normal);
philpem@5 5899
philpem@5 5900 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path());
philpem@5 5901 cimg_std::fprintf(cimg_stdout," > Path of GraphicsMagick : %s%-13s%s\n",
philpem@5 5902 cimg::t_bold,
philpem@5 5903 tmp,
philpem@5 5904 cimg::t_normal);
philpem@5 5905
philpem@5 5906 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path());
philpem@5 5907 cimg_std::fprintf(cimg_stdout," > Path of 'medcon' : %s%-13s%s\n",
philpem@5 5908 cimg::t_bold,
philpem@5 5909 tmp,
philpem@5 5910 cimg::t_normal);
philpem@5 5911
philpem@5 5912 cimg_std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path());
philpem@5 5913 cimg_std::fprintf(cimg_stdout," > Temporary path : %s%-13s%s\n",
philpem@5 5914 cimg::t_bold,
philpem@5 5915 tmp,
philpem@5 5916 cimg::t_normal);
philpem@5 5917
philpem@5 5918 cimg_std::fprintf(cimg_stdout,"\n");
philpem@5 5919 }
philpem@5 5920
philpem@5 5921 // Declare LAPACK function signatures if necessary.
philpem@5 5922 //
philpem@5 5923 #ifdef cimg_use_lapack
philpem@5 5924 template<typename T>
philpem@5 5925 inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) {
philpem@5 5926 dgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
philpem@5 5927 }
philpem@5 5928
philpem@5 5929 inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) {
philpem@5 5930 sgetrf_(&N,&N,lapA,&N,IPIV,&INFO);
philpem@5 5931 }
philpem@5 5932
philpem@5 5933 template<typename T>
philpem@5 5934 inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) {
philpem@5 5935 dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
philpem@5 5936 }
philpem@5 5937
philpem@5 5938 inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) {
philpem@5 5939 sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO);
philpem@5 5940 }
philpem@5 5941
philpem@5 5942 template<typename T>
philpem@5 5943 inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN,
philpem@5 5944 T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) {
philpem@5 5945 dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
philpem@5 5946 }
philpem@5 5947
philpem@5 5948 inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN,
philpem@5 5949 float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) {
philpem@5 5950 sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO);
philpem@5 5951 }
philpem@5 5952
philpem@5 5953 template<typename T>
philpem@5 5954 inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) {
philpem@5 5955 int one = 1;
philpem@5 5956 dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
philpem@5 5957 }
philpem@5 5958
philpem@5 5959 inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) {
philpem@5 5960 int one = 1;
philpem@5 5961 sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO);
philpem@5 5962 }
philpem@5 5963
philpem@5 5964 template<typename T>
philpem@5 5965 inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) {
philpem@5 5966 dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
philpem@5 5967 }
philpem@5 5968
philpem@5 5969 inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) {
philpem@5 5970 ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO);
philpem@5 5971 }
philpem@5 5972 #endif
philpem@5 5973
philpem@5 5974 // End of the 'cimg' namespace
philpem@5 5975 }
philpem@5 5976
philpem@5 5977 /*------------------------------------------------
philpem@5 5978 #
philpem@5 5979 #
philpem@5 5980 # Definition of mathematical operators and
philpem@5 5981 # external functions.
philpem@5 5982 #
philpem@5 5983 #
philpem@5 5984 -------------------------------------------------*/
philpem@5 5985 //
philpem@5 5986 // These functions are extern to any classes and can be used for a "functional-style" programming,
philpem@5 5987 // such as writting :
philpem@5 5988 // cos(img);
philpem@5 5989 // instead of img.get_cos();
philpem@5 5990 //
philpem@5 5991 // Note that only the arithmetic operators and functions are implemented here.
philpem@5 5992 //
philpem@5 5993
philpem@5 5994 #ifdef cimg_use_visualcpp6
philpem@5 5995 template<typename t>
philpem@5 5996 inline CImg<t> operator+(const CImg<t>& img, const t val) {
philpem@5 5997 return CImg<t>(img,false)+=val;
philpem@5 5998 }
philpem@5 5999 #else
philpem@5 6000 template<typename t1, typename t2>
philpem@5 6001 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const t2 val) {
philpem@5 6002 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6003 return CImg<t1t2>(img,false)+=val;
philpem@5 6004 }
philpem@5 6005 #endif
philpem@5 6006
philpem@5 6007 #ifdef cimg_use_visualcpp6
philpem@5 6008 template<typename t>
philpem@5 6009 inline CImg<t> operator+(const t val, const CImg<t>& img) {
philpem@5 6010 return img + val;
philpem@5 6011 }
philpem@5 6012 #else
philpem@5 6013 template<typename t1, typename t2>
philpem@5 6014 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImg<t2>& img) {
philpem@5 6015 return img + val;
philpem@5 6016 }
philpem@5 6017 #endif
philpem@5 6018
philpem@5 6019 #ifdef cimg_use_visualcpp6
philpem@5 6020 template<typename t>
philpem@5 6021 inline CImgList<t> operator+(const CImgList<t>& list, const t val) {
philpem@5 6022 return CImgList<t>(list)+=val;
philpem@5 6023 }
philpem@5 6024 #else
philpem@5 6025 template<typename t1, typename t2>
philpem@5 6026 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const t2 val) {
philpem@5 6027 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6028 return CImgList<t1t2>(list)+=val;
philpem@5 6029 }
philpem@5 6030 #endif
philpem@5 6031
philpem@5 6032 #ifdef cimg_use_visualcpp6
philpem@5 6033 template<typename t>
philpem@5 6034 inline CImgList<t> operator+(const t val, const CImgList<t>& list) {
philpem@5 6035 return list + val;
philpem@5 6036 }
philpem@5 6037 #else
philpem@5 6038 template<typename t1, typename t2>
philpem@5 6039 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const t1 val, const CImgList<t2>& list) {
philpem@5 6040 return list + val;
philpem@5 6041 }
philpem@5 6042 #endif
philpem@5 6043
philpem@5 6044 template<typename t1, typename t2>
philpem@5 6045 inline CImg<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) {
philpem@5 6046 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6047 return CImg<t1t2>(img1,false)+=img2;
philpem@5 6048 }
philpem@5 6049
philpem@5 6050 template<typename t1, typename t2>
philpem@5 6051 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) {
philpem@5 6052 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6053 return CImgList<t1t2>(list)+=img;
philpem@5 6054 }
philpem@5 6055
philpem@5 6056 template<typename t1, typename t2>
philpem@5 6057 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) {
philpem@5 6058 return img + list;
philpem@5 6059 }
philpem@5 6060
philpem@5 6061 template<typename t1, typename t2>
philpem@5 6062 inline CImgList<typename cimg::superset<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) {
philpem@5 6063 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6064 return CImgList<t1t2>(list1)+=list2;
philpem@5 6065 }
philpem@5 6066
philpem@5 6067 #ifdef cimg_use_visualcpp6
philpem@5 6068 template<typename t>
philpem@5 6069 inline CImg<t> operator-(const CImg<t>& img, const t val) {
philpem@5 6070 return CImg<t>(img,false)-=val;
philpem@5 6071 }
philpem@5 6072 #else
philpem@5 6073 template<typename t1, typename t2>
philpem@5 6074 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const t2 val) {
philpem@5 6075 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6076 return CImg<t1t2>(img,false)-=val;
philpem@5 6077 }
philpem@5 6078 #endif
philpem@5 6079
philpem@5 6080 #ifdef cimg_use_visualcpp6
philpem@5 6081 template<typename t>
philpem@5 6082 inline CImg<t> operator-(const t val, const CImg<t>& img) {
philpem@5 6083 return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img;
philpem@5 6084 }
philpem@5 6085 #else
philpem@5 6086 template<typename t1, typename t2>
philpem@5 6087 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImg<t2>& img) {
philpem@5 6088 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6089 return CImg<t1t2>(img.width,img.height,img.depth,img.dim,(t1t2)val)-=img;
philpem@5 6090 }
philpem@5 6091 #endif
philpem@5 6092
philpem@5 6093 #ifdef cimg_use_visualcpp6
philpem@5 6094 template<typename t>
philpem@5 6095 inline CImgList<t> operator-(const CImgList<t>& list, const t val) {
philpem@5 6096 return CImgList<t>(list)-=val;
philpem@5 6097 }
philpem@5 6098 #else
philpem@5 6099 template<typename t1, typename t2>
philpem@5 6100 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const t2 val) {
philpem@5 6101 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6102 return CImgList<t1t2>(list)-=val;
philpem@5 6103 }
philpem@5 6104 #endif
philpem@5 6105
philpem@5 6106 #ifdef cimg_use_visualcpp6
philpem@5 6107 template<typename t>
philpem@5 6108 inline CImgList<double> operator-(const t val, const CImgList<t>& list) {
philpem@5 6109 CImgList<t> res(list.size);
philpem@5 6110 cimglist_for(res,l) res[l] = val - list[l];
philpem@5 6111 return res;
philpem@5 6112 }
philpem@5 6113 #else
philpem@5 6114 template<typename t1, typename t2>
philpem@5 6115 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const t1 val, const CImgList<t2>& list) {
philpem@5 6116 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6117 CImgList<t1t2> res(list.size);
philpem@5 6118 cimglist_for(res,l) res[l] = val - list[l];
philpem@5 6119 return res;
philpem@5 6120 }
philpem@5 6121 #endif
philpem@5 6122
philpem@5 6123 template<typename t1, typename t2>
philpem@5 6124 inline CImg<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) {
philpem@5 6125 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6126 return CImg<t1t2>(img1,false)-=img2;
philpem@5 6127 }
philpem@5 6128
philpem@5 6129 template<typename t1, typename t2>
philpem@5 6130 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) {
philpem@5 6131 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6132 CImgList<t1t2> res(list.size);
philpem@5 6133 cimglist_for(res,l) res[l] = img - list[l];
philpem@5 6134 return res;
philpem@5 6135 }
philpem@5 6136
philpem@5 6137 template<typename t1, typename t2>
philpem@5 6138 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) {
philpem@5 6139 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6140 return CImgList<t1t2>(list)-=img;
philpem@5 6141 }
philpem@5 6142
philpem@5 6143 template<typename t1, typename t2>
philpem@5 6144 inline CImgList<typename cimg::superset<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) {
philpem@5 6145 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6146 return CImgList<t1t2>(list1)-=list2;
philpem@5 6147 }
philpem@5 6148
philpem@5 6149 #ifdef cimg_use_visualcpp6
philpem@5 6150 template<typename t>
philpem@5 6151 inline CImg<t> operator*(const CImg<t>& img, const double val) {
philpem@5 6152 return CImg<t>(img,false)*=val;
philpem@5 6153 }
philpem@5 6154 #else
philpem@5 6155 template<typename t1, typename t2>
philpem@5 6156 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const t2 val) {
philpem@5 6157 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6158 return CImg<t1t2>(img,false)*=val;
philpem@5 6159 }
philpem@5 6160 #endif
philpem@5 6161
philpem@5 6162 #ifdef cimg_use_visualcpp6
philpem@5 6163 template<typename t>
philpem@5 6164 inline CImg<t> operator*(const double val, const CImg<t>& img) {
philpem@5 6165 return img*val;
philpem@5 6166 }
philpem@5 6167 #else
philpem@5 6168 template<typename t1, typename t2>
philpem@5 6169 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImg<t2>& img) {
philpem@5 6170 return img*val;
philpem@5 6171 }
philpem@5 6172 #endif
philpem@5 6173
philpem@5 6174 #ifdef cimg_use_visualcpp6
philpem@5 6175 template<typename t>
philpem@5 6176 inline CImgList<t> operator*(const CImgList<t>& list, const double val) {
philpem@5 6177 return CImgList<t>(list)*=val;
philpem@5 6178 }
philpem@5 6179 #else
philpem@5 6180 template<typename t1, typename t2>
philpem@5 6181 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const t2 val) {
philpem@5 6182 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6183 return CImgList<t1t2>(list)*=val;
philpem@5 6184 }
philpem@5 6185 #endif
philpem@5 6186
philpem@5 6187 #ifdef cimg_use_visualcpp6
philpem@5 6188 template<typename t>
philpem@5 6189 inline CImgList<t> operator*(const double val, const CImgList<t>& list) {
philpem@5 6190 return list*val;
philpem@5 6191 }
philpem@5 6192 #else
philpem@5 6193 template<typename t1, typename t2>
philpem@5 6194 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const t1 val, const CImgList<t2>& list) {
philpem@5 6195 return list*val;
philpem@5 6196 }
philpem@5 6197 #endif
philpem@5 6198
philpem@5 6199 template<typename t1, typename t2>
philpem@5 6200 inline CImg<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) {
philpem@5 6201 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6202 if (img1.width!=img2.height)
philpem@5 6203 throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)",
philpem@5 6204 img1.width,img1.height,img2.width,img2.height);
philpem@5 6205 CImg<t1t2> res(img2.width,img1.height);
philpem@5 6206 t1t2 val;
philpem@5 6207 #ifdef cimg_use_openmp
philpem@5 6208 #pragma omp parallel for if (img1.size()>=1000 && img2.size()>=1000) private(val)
philpem@5 6209 #endif
philpem@5 6210 cimg_forXY(res,i,j) { val = 0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; }
philpem@5 6211 return res;
philpem@5 6212 }
philpem@5 6213
philpem@5 6214 template<typename t1, typename t2>
philpem@5 6215 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) {
philpem@5 6216 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6217 CImgList<t1t2> res(list.size);
philpem@5 6218 cimglist_for(res,l) res[l] = img*list[l];
philpem@5 6219 return res;
philpem@5 6220 }
philpem@5 6221
philpem@5 6222 template<typename t1, typename t2>
philpem@5 6223 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) {
philpem@5 6224 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6225 CImgList<t1t2> res(list.size);
philpem@5 6226 cimglist_for(res,l) res[l] = list[l]*img;
philpem@5 6227 return res;
philpem@5 6228 }
philpem@5 6229
philpem@5 6230 template<typename t1, typename t2>
philpem@5 6231 inline CImgList<typename cimg::superset<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) {
philpem@5 6232 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6233 CImgList<t1t2> res(cimg::min(list1.size,list2.size));
philpem@5 6234 cimglist_for(res,l) res[l] = list1[l]*list2[l];
philpem@5 6235 return res;
philpem@5 6236 }
philpem@5 6237
philpem@5 6238 #ifdef cimg_use_visualcpp6
philpem@5 6239 template<typename t>
philpem@5 6240 inline CImg<t> operator/(const CImg<t>& img, const double val) {
philpem@5 6241 return CImg<t>(img,false)/=val;
philpem@5 6242 }
philpem@5 6243 #else
philpem@5 6244 template<typename t1, typename t2>
philpem@5 6245 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const t2 val) {
philpem@5 6246 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6247 return CImg<t1t2>(img,false)/=val;
philpem@5 6248 }
philpem@5 6249 #endif
philpem@5 6250
philpem@5 6251 #ifdef cimg_use_visualcpp6
philpem@5 6252 template<typename t>
philpem@5 6253 inline CImg<t> operator/(const double val, CImg<t>& img) {
philpem@5 6254 return val*img.get_invert();
philpem@5 6255 }
philpem@5 6256 #else
philpem@5 6257 template<typename t1, typename t2>
philpem@5 6258 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const t1 val, CImg<t2>& img) {
philpem@5 6259 return val*img.get_invert();
philpem@5 6260 }
philpem@5 6261 #endif
philpem@5 6262
philpem@5 6263 #ifdef cimg_use_visualcpp6
philpem@5 6264 template<typename t>
philpem@5 6265 inline CImgList<t> operator/(const CImgList<t>& list, const double val) {
philpem@5 6266 return CImgList<t>(list)/=val;
philpem@5 6267 }
philpem@5 6268 #else
philpem@5 6269 template<typename t1, typename t2>
philpem@5 6270 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const t2 val) {
philpem@5 6271 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6272 return CImgList<t1t2>(list)/=val;
philpem@5 6273 }
philpem@5 6274 #endif
philpem@5 6275
philpem@5 6276 #ifdef cimg_use_visualcpp6
philpem@5 6277 template<typename t>
philpem@5 6278 inline CImgList<t> operator/(const double val, const CImgList<t>& list) {
philpem@5 6279 CImgList<t> res(list.size);
philpem@5 6280 cimglist_for(res,l) res[l] = val/list[l];
philpem@5 6281 return res;
philpem@5 6282 }
philpem@5 6283 #else
philpem@5 6284 template<typename t1, typename t2>
philpem@5 6285 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const t1 val, const CImgList<t2>& list) {
philpem@5 6286 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6287 CImgList<t1t2> res(list.size);
philpem@5 6288 cimglist_for(res,l) res[l] = val/list[l];
philpem@5 6289 return res;
philpem@5 6290 }
philpem@5 6291 #endif
philpem@5 6292
philpem@5 6293 template<typename t1, typename t2>
philpem@5 6294 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) {
philpem@5 6295 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6296 return CImg<t1t2>(img1,false)*=img2.get_invert();
philpem@5 6297 }
philpem@5 6298
philpem@5 6299 template<typename t1, typename t2>
philpem@5 6300 inline CImg<typename cimg::superset<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) {
philpem@5 6301 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6302 CImgList<t1t2> res(list.size);
philpem@5 6303 cimglist_for(res,l) res[l] = img/list[l];
philpem@5 6304 return res;
philpem@5 6305 }
philpem@5 6306
philpem@5 6307 template<typename t1, typename t2>
philpem@5 6308 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) {
philpem@5 6309 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6310 return CImgList<t1t2>(list)/=img;
philpem@5 6311 }
philpem@5 6312
philpem@5 6313 template<typename t1, typename t2>
philpem@5 6314 inline CImgList<typename cimg::superset<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) {
philpem@5 6315 typedef typename cimg::superset<t1,t2>::type t1t2;
philpem@5 6316 return CImgList<t1t2>(list1)/=list2;
philpem@5 6317 }
philpem@5 6318
philpem@5 6319 template<typename T>
philpem@5 6320 inline CImg<_cimg_Tfloat> sqr(const CImg<T>& instance) {
philpem@5 6321 return instance.get_sqr();
philpem@5 6322 }
philpem@5 6323
philpem@5 6324 template<typename T>
philpem@5 6325 inline CImg<_cimg_Tfloat> sqrt(const CImg<T>& instance) {
philpem@5 6326 return instance.get_sqrt();
philpem@5 6327 }
philpem@5 6328
philpem@5 6329 template<typename T>
philpem@5 6330 inline CImg<_cimg_Tfloat> exp(const CImg<T>& instance) {
philpem@5 6331 return instance.get_exp();
philpem@5 6332 }
philpem@5 6333
philpem@5 6334 template<typename T>
philpem@5 6335 inline CImg<_cimg_Tfloat> log(const CImg<T>& instance) {
philpem@5 6336 return instance.get_log();
philpem@5 6337 }
philpem@5 6338
philpem@5 6339 template<typename T>
philpem@5 6340 inline CImg<_cimg_Tfloat> log10(const CImg<T>& instance) {
philpem@5 6341 return instance.get_log10();
philpem@5 6342 }
philpem@5 6343
philpem@5 6344 template<typename T>
philpem@5 6345 inline CImg<_cimg_Tfloat> abs(const CImg<T>& instance) {
philpem@5 6346 return instance.get_abs();
philpem@5 6347 }
philpem@5 6348
philpem@5 6349 template<typename T>
philpem@5 6350 inline CImg<_cimg_Tfloat> cos(const CImg<T>& instance) {
philpem@5 6351 return instance.get_cos();
philpem@5 6352 }
philpem@5 6353
philpem@5 6354 template<typename T>
philpem@5 6355 inline CImg<_cimg_Tfloat> sin(const CImg<T>& instance) {
philpem@5 6356 return instance.get_sin();
philpem@5 6357 }
philpem@5 6358
philpem@5 6359 template<typename T>
philpem@5 6360 inline CImg<_cimg_Tfloat> tan(const CImg<T>& instance) {
philpem@5 6361 return instance.get_tan();
philpem@5 6362 }
philpem@5 6363
philpem@5 6364 template<typename T>
philpem@5 6365 inline CImg<_cimg_Tfloat> acos(const CImg<T>& instance) {
philpem@5 6366 return instance.get_acos();
philpem@5 6367 }
philpem@5 6368
philpem@5 6369 template<typename T>
philpem@5 6370 inline CImg<_cimg_Tfloat> asin(const CImg<T>& instance) {
philpem@5 6371 return instance.get_asin();
philpem@5 6372 }
philpem@5 6373
philpem@5 6374 template<typename T>
philpem@5 6375 inline CImg<_cimg_Tfloat> atan(const CImg<T>& instance) {
philpem@5 6376 return instance.get_atan();
philpem@5 6377 }
philpem@5 6378
philpem@5 6379 template<typename T>
philpem@5 6380 inline CImg<T> transpose(const CImg<T>& instance) {
philpem@5 6381 return instance.get_transpose();
philpem@5 6382 }
philpem@5 6383
philpem@5 6384 template<typename T>
philpem@5 6385 inline CImg<_cimg_Tfloat> invert(const CImg<T>& instance) {
philpem@5 6386 return instance.get_invert();
philpem@5 6387 }
philpem@5 6388
philpem@5 6389 template<typename T>
philpem@5 6390 inline CImg<_cimg_Tfloat> pseudoinvert(const CImg<T>& instance) {
philpem@5 6391 return instance.get_pseudoinvert();
philpem@5 6392 }
philpem@5 6393
philpem@5 6394 /*-------------------------------------------
philpem@5 6395 #
philpem@5 6396 #
philpem@5 6397 #
philpem@5 6398 # Definition of the CImgDisplay structure
philpem@5 6399 #
philpem@5 6400 #
philpem@5 6401 #
philpem@5 6402 --------------------------------------------*/
philpem@5 6403
philpem@5 6404 //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events.
philpem@5 6405 /**
philpem@5 6406 Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg<T> image
philpem@5 6407 of a \c CImgList<T> image list inside. When a display is created, associated window events
philpem@5 6408 (such as mouse motion, keyboard and window size changes) are handled and can be easily
philpem@5 6409 detected by testing specific \c CImgDisplay data fields.
philpem@5 6410 See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class.
philpem@5 6411 **/
philpem@5 6412
philpem@5 6413 struct CImgDisplay {
philpem@5 6414
philpem@5 6415 //! Width of the display
philpem@5 6416 unsigned int width;
philpem@5 6417
philpem@5 6418 //! Height of the display
philpem@5 6419 unsigned int height;
philpem@5 6420
philpem@5 6421 //! Normalization type used for the display
philpem@5 6422 unsigned int normalization;
philpem@5 6423
philpem@5 6424 //! Display title
philpem@5 6425 char* title;
philpem@5 6426
philpem@5 6427 //! X-pos of the display on the screen
philpem@5 6428 volatile int window_x;
philpem@5 6429
philpem@5 6430 //! Y-pos of the display on the screen
philpem@5 6431 volatile int window_y;
philpem@5 6432
philpem@5 6433 //! Width of the underlying window
philpem@5 6434 volatile unsigned int window_width;
philpem@5 6435
philpem@5 6436 //! Height of the underlying window
philpem@5 6437 volatile unsigned int window_height;
philpem@5 6438
philpem@5 6439 //! X-coordinate of the mouse pointer on the display
philpem@5 6440 volatile int mouse_x;
philpem@5 6441
philpem@5 6442 //! Y-coordinate of the mouse pointer on the display
philpem@5 6443 volatile int mouse_y;
philpem@5 6444
philpem@5 6445 //! Button state of the mouse
philpem@5 6446 volatile unsigned int buttons[512];
philpem@5 6447 volatile unsigned int& button;
philpem@5 6448
philpem@5 6449 //! Wheel state of the mouse
philpem@5 6450 volatile int wheel;
philpem@5 6451
philpem@5 6452 //! Key value if pressed
philpem@5 6453 volatile unsigned int& key;
philpem@5 6454 volatile unsigned int keys[512];
philpem@5 6455
philpem@5 6456 //! Key value if released
philpem@5 6457 volatile unsigned int& released_key;
philpem@5 6458 volatile unsigned int released_keys[512];
philpem@5 6459
philpem@5 6460 //! Closed state of the window
philpem@5 6461 volatile bool is_closed;
philpem@5 6462
philpem@5 6463 //! Resized state of the window
philpem@5 6464 volatile bool is_resized;
philpem@5 6465
philpem@5 6466 //! Moved state of the window
philpem@5 6467 volatile bool is_moved;
philpem@5 6468
philpem@5 6469 //! Event state of the window
philpem@5 6470 volatile bool is_event;
philpem@5 6471
philpem@5 6472 //! Current state of the corresponding key (exists for all referenced keys).
philpem@5 6473 volatile bool is_keyESC;
philpem@5 6474 volatile bool is_keyF1;
philpem@5 6475 volatile bool is_keyF2;
philpem@5 6476 volatile bool is_keyF3;
philpem@5 6477 volatile bool is_keyF4;
philpem@5 6478 volatile bool is_keyF5;
philpem@5 6479 volatile bool is_keyF6;
philpem@5 6480 volatile bool is_keyF7;
philpem@5 6481 volatile bool is_keyF8;
philpem@5 6482 volatile bool is_keyF9;
philpem@5 6483 volatile bool is_keyF10;
philpem@5 6484 volatile bool is_keyF11;
philpem@5 6485 volatile bool is_keyF12;
philpem@5 6486 volatile bool is_keyPAUSE;
philpem@5 6487 volatile bool is_key1;
philpem@5 6488 volatile bool is_key2;
philpem@5 6489 volatile bool is_key3;
philpem@5 6490 volatile bool is_key4;
philpem@5 6491 volatile bool is_key5;
philpem@5 6492 volatile bool is_key6;
philpem@5 6493 volatile bool is_key7;
philpem@5 6494 volatile bool is_key8;
philpem@5 6495 volatile bool is_key9;
philpem@5 6496 volatile bool is_key0;
philpem@5 6497 volatile bool is_keyBACKSPACE;
philpem@5 6498 volatile bool is_keyINSERT;
philpem@5 6499 volatile bool is_keyHOME;
philpem@5 6500 volatile bool is_keyPAGEUP;
philpem@5 6501 volatile bool is_keyTAB;
philpem@5 6502 volatile bool is_keyQ;
philpem@5 6503 volatile bool is_keyW;
philpem@5 6504 volatile bool is_keyE;
philpem@5 6505 volatile bool is_keyR;
philpem@5 6506 volatile bool is_keyT;
philpem@5 6507 volatile bool is_keyY;
philpem@5 6508 volatile bool is_keyU;
philpem@5 6509 volatile bool is_keyI;
philpem@5 6510 volatile bool is_keyO;
philpem@5 6511 volatile bool is_keyP;
philpem@5 6512 volatile bool is_keyDELETE;
philpem@5 6513 volatile bool is_keyEND;
philpem@5 6514 volatile bool is_keyPAGEDOWN;
philpem@5 6515 volatile bool is_keyCAPSLOCK;
philpem@5 6516 volatile bool is_keyA;
philpem@5 6517 volatile bool is_keyS;
philpem@5 6518 volatile bool is_keyD;
philpem@5 6519 volatile bool is_keyF;
philpem@5 6520 volatile bool is_keyG;
philpem@5 6521 volatile bool is_keyH;
philpem@5 6522 volatile bool is_keyJ;
philpem@5 6523 volatile bool is_keyK;
philpem@5 6524 volatile bool is_keyL;
philpem@5 6525 volatile bool is_keyENTER;
philpem@5 6526 volatile bool is_keySHIFTLEFT;
philpem@5 6527 volatile bool is_keyZ;
philpem@5 6528 volatile bool is_keyX;
philpem@5 6529 volatile bool is_keyC;
philpem@5 6530 volatile bool is_keyV;
philpem@5 6531 volatile bool is_keyB;
philpem@5 6532 volatile bool is_keyN;
philpem@5 6533 volatile bool is_keyM;
philpem@5 6534 volatile bool is_keySHIFTRIGHT;
philpem@5 6535 volatile bool is_keyARROWUP;
philpem@5 6536 volatile bool is_keyCTRLLEFT;
philpem@5 6537 volatile bool is_keyAPPLEFT;
philpem@5 6538 volatile bool is_keyALT;
philpem@5 6539 volatile bool is_keySPACE;
philpem@5 6540 volatile bool is_keyALTGR;
philpem@5 6541 volatile bool is_keyAPPRIGHT;
philpem@5 6542 volatile bool is_keyMENU;
philpem@5 6543 volatile bool is_keyCTRLRIGHT;
philpem@5 6544 volatile bool is_keyARROWLEFT;
philpem@5 6545 volatile bool is_keyARROWDOWN;
philpem@5 6546 volatile bool is_keyARROWRIGHT;
philpem@5 6547 volatile bool is_keyPAD0;
philpem@5 6548 volatile bool is_keyPAD1;
philpem@5 6549 volatile bool is_keyPAD2;
philpem@5 6550 volatile bool is_keyPAD3;
philpem@5 6551 volatile bool is_keyPAD4;
philpem@5 6552 volatile bool is_keyPAD5;
philpem@5 6553 volatile bool is_keyPAD6;
philpem@5 6554 volatile bool is_keyPAD7;
philpem@5 6555 volatile bool is_keyPAD8;
philpem@5 6556 volatile bool is_keyPAD9;
philpem@5 6557 volatile bool is_keyPADADD;
philpem@5 6558 volatile bool is_keyPADSUB;
philpem@5 6559 volatile bool is_keyPADMUL;
philpem@5 6560 volatile bool is_keyPADDIV;
philpem@5 6561
philpem@5 6562 //! Fullscreen state of the display
philpem@5 6563 bool is_fullscreen;
philpem@5 6564
philpem@5 6565 float fps_fps, min, max;
philpem@5 6566 unsigned long timer, fps_frames, fps_timer;
philpem@5 6567
philpem@5 6568 #ifdef cimgdisplay_plugin
philpem@5 6569 #include cimgdisplay_plugin
philpem@5 6570 #endif
philpem@5 6571 #ifdef cimgdisplay_plugin1
philpem@5 6572 #include cimgdisplay_plugin1
philpem@5 6573 #endif
philpem@5 6574 #ifdef cimgdisplay_plugin2
philpem@5 6575 #include cimgdisplay_plugin2
philpem@5 6576 #endif
philpem@5 6577 #ifdef cimgdisplay_plugin3
philpem@5 6578 #include cimgdisplay_plugin3
philpem@5 6579 #endif
philpem@5 6580 #ifdef cimgdisplay_plugin4
philpem@5 6581 #include cimgdisplay_plugin4
philpem@5 6582 #endif
philpem@5 6583 #ifdef cimgdisplay_plugin5
philpem@5 6584 #include cimgdisplay_plugin5
philpem@5 6585 #endif
philpem@5 6586 #ifdef cimgdisplay_plugin6
philpem@5 6587 #include cimgdisplay_plugin6
philpem@5 6588 #endif
philpem@5 6589 #ifdef cimgdisplay_plugin7
philpem@5 6590 #include cimgdisplay_plugin7
philpem@5 6591 #endif
philpem@5 6592 #ifdef cimgdisplay_plugin8
philpem@5 6593 #include cimgdisplay_plugin8
philpem@5 6594 #endif
philpem@5 6595
philpem@5 6596 //! Create an empty display window.
philpem@5 6597 CImgDisplay():
philpem@5 6598 width(0),height(0),normalization(0),title(0),
philpem@5 6599 window_x(0),window_y(0),window_width(0),window_height(0),
philpem@5 6600 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
philpem@5 6601 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
philpem@5 6602 min(0),max(0) {}
philpem@5 6603
philpem@5 6604 //! Create a display window with a specified size \p pwidth x \p height.
philpem@5 6605 /** \param dimw Width of the display window.
philpem@5 6606 \param dimh Height of the display window.
philpem@5 6607 \param title Title of the display window.
philpem@5 6608 \param normalization_type Normalization type of the display window (0=none, 1=always, 2=once).
philpem@5 6609 \param fullscreen_flag : Fullscreen mode.
philpem@5 6610 \param closed_flag : Initially visible mode.
philpem@5 6611 A black image will be initially displayed in the display window.
philpem@5 6612 **/
philpem@5 6613 CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0,
philpem@5 6614 const unsigned int normalization_type=3,
philpem@5 6615 const bool fullscreen_flag=false, const bool closed_flag=false):
philpem@5 6616 width(0),height(0),normalization(0),title(0),
philpem@5 6617 window_x(0),window_y(0),window_width(0),window_height(0),
philpem@5 6618 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
philpem@5 6619 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),
philpem@5 6620 min(0),max(0) {
philpem@5 6621 assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 6622 }
philpem@5 6623
philpem@5 6624 //! Create a display window from an image.
philpem@5 6625 /** \param img : Image that will be used to create the display window.
philpem@5 6626 \param title : Title of the display window
philpem@5 6627 \param normalization_type : Normalization type of the display window.
philpem@5 6628 \param fullscreen_flag : Fullscreen mode.
philpem@5 6629 \param closed_flag : Initially visible mode.
philpem@5 6630 **/
philpem@5 6631 template<typename T>
philpem@5 6632 CImgDisplay(const CImg<T>& img, const char *title=0,
philpem@5 6633 const unsigned int normalization_type=3,
philpem@5 6634 const bool fullscreen_flag=false, const bool closed_flag=false):
philpem@5 6635 width(0),height(0),normalization(0),title(0),
philpem@5 6636 window_x(0),window_y(0),window_width(0),window_height(0),
philpem@5 6637 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
philpem@5 6638 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
philpem@5 6639 assign(img,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 6640 }
philpem@5 6641
philpem@5 6642 //! Create a display window from an image list.
philpem@5 6643 /** \param list : The list of images to display.
philpem@5 6644 \param title : Title of the display window
philpem@5 6645 \param normalization_type : Normalization type of the display window.
philpem@5 6646 \param fullscreen_flag : Fullscreen mode.
philpem@5 6647 \param closed_flag : Initially visible mode.
philpem@5 6648 **/
philpem@5 6649 template<typename T>
philpem@5 6650 CImgDisplay(const CImgList<T>& list, const char *title=0,
philpem@5 6651 const unsigned int normalization_type=3,
philpem@5 6652 const bool fullscreen_flag=false, const bool closed_flag=false):
philpem@5 6653 width(0),height(0),normalization(0),title(0),
philpem@5 6654 window_x(0),window_y(0),window_width(0),window_height(0),
philpem@5 6655 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
philpem@5 6656 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
philpem@5 6657 assign(list,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 6658 }
philpem@5 6659
philpem@5 6660 //! Create a display window by copying another one.
philpem@5 6661 /**
philpem@5 6662 \param disp : Display window to copy.
philpem@5 6663 **/
philpem@5 6664 CImgDisplay(const CImgDisplay& disp):
philpem@5 6665 width(0),height(0),normalization(0),title(0),
philpem@5 6666 window_x(0),window_y(0),window_width(0),window_height(0),
philpem@5 6667 mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys),
philpem@5 6668 is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) {
philpem@5 6669 assign(disp);
philpem@5 6670 }
philpem@5 6671
philpem@5 6672 //! Destructor.
philpem@5 6673 ~CImgDisplay() {
philpem@5 6674 assign();
philpem@5 6675 }
philpem@5 6676
philpem@5 6677 //! Assignment operator.
philpem@5 6678 CImgDisplay& operator=(const CImgDisplay& disp) {
philpem@5 6679 return assign(disp);
philpem@5 6680 }
philpem@5 6681
philpem@5 6682 //! Return true is display is empty.
philpem@5 6683 bool is_empty() const {
philpem@5 6684 return (!width || !height);
philpem@5 6685 }
philpem@5 6686
philpem@5 6687 //! Return true if display is not empty.
philpem@5 6688 operator bool() const {
philpem@5 6689 return !is_empty();
philpem@5 6690 }
philpem@5 6691
philpem@5 6692 //! Return display width.
philpem@5 6693 int dimx() const {
philpem@5 6694 return (int)width;
philpem@5 6695 }
philpem@5 6696
philpem@5 6697 //! Return display height.
philpem@5 6698 int dimy() const {
philpem@5 6699 return (int)height;
philpem@5 6700 }
philpem@5 6701
philpem@5 6702 //! Return display window width.
philpem@5 6703 int window_dimx() const {
philpem@5 6704 return (int)window_width;
philpem@5 6705 }
philpem@5 6706
philpem@5 6707 //! Return display window height.
philpem@5 6708 int window_dimy() const {
philpem@5 6709 return (int)window_height;
philpem@5 6710 }
philpem@5 6711
philpem@5 6712 //! Return X-coordinate of the window.
philpem@5 6713 int window_posx() const {
philpem@5 6714 return window_x;
philpem@5 6715 }
philpem@5 6716
philpem@5 6717 //! Return Y-coordinate of the window.
philpem@5 6718 int window_posy() const {
philpem@5 6719 return window_y;
philpem@5 6720 }
philpem@5 6721
philpem@5 6722 //! Synchronized waiting function. Same as cimg::wait().
philpem@5 6723 CImgDisplay& wait(const unsigned int milliseconds) {
philpem@5 6724 cimg::_sleep(milliseconds,timer);
philpem@5 6725 return *this;
philpem@5 6726 }
philpem@5 6727
philpem@5 6728 //! Wait for an event occuring on the current display.
philpem@5 6729 CImgDisplay& wait() {
philpem@5 6730 if (!is_empty()) wait(*this);
philpem@5 6731 return *this;
philpem@5 6732 }
philpem@5 6733
philpem@5 6734 //! Wait for any event occuring on the display \c disp1.
philpem@5 6735 static void wait(CImgDisplay& disp1) {
philpem@5 6736 disp1.is_event = 0;
philpem@5 6737 while (!disp1.is_event) wait_all();
philpem@5 6738 }
philpem@5 6739
philpem@5 6740 //! Wait for any event occuring either on the display \c disp1 or \c disp2.
philpem@5 6741 static void wait(CImgDisplay& disp1, CImgDisplay& disp2) {
philpem@5 6742 disp1.is_event = disp2.is_event = 0;
philpem@5 6743 while (!disp1.is_event && !disp2.is_event) wait_all();
philpem@5 6744 }
philpem@5 6745
philpem@5 6746 //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3.
philpem@5 6747 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) {
philpem@5 6748 disp1.is_event = disp2.is_event = disp3.is_event = 0;
philpem@5 6749 while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all();
philpem@5 6750 }
philpem@5 6751
philpem@5 6752 //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4.
philpem@5 6753 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) {
philpem@5 6754 disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0;
philpem@5 6755 while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all();
philpem@5 6756 }
philpem@5 6757
philpem@5 6758 //! Return the frame per second rate.
philpem@5 6759 float frames_per_second() {
philpem@5 6760 if (!fps_timer) fps_timer = cimg::time();
philpem@5 6761 const float delta = (cimg::time()-fps_timer)/1000.0f;
philpem@5 6762 ++fps_frames;
philpem@5 6763 if (delta>=1) {
philpem@5 6764 fps_fps = fps_frames/delta;
philpem@5 6765 fps_frames = 0;
philpem@5 6766 fps_timer = cimg::time();
philpem@5 6767 }
philpem@5 6768 return fps_fps;
philpem@5 6769 }
philpem@5 6770
philpem@5 6771 //! Display an image list CImgList<T> into a display window.
philpem@5 6772 /** First, all images of the list are appended into a single image used for visualization,
philpem@5 6773 then this image is displayed in the current display window.
philpem@5 6774 \param list : The list of images to display.
philpem@5 6775 \param axis : The axis used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'.
philpem@5 6776 \param align : Defines the relative alignment of images when displaying images of different sizes.
philpem@5 6777 Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment).
philpem@5 6778 **/
philpem@5 6779 template<typename T>
philpem@5 6780 CImgDisplay& display(const CImgList<T>& list, const char axis='x', const char align='p') {
philpem@5 6781 return display(list.get_append(axis,align));
philpem@5 6782 }
philpem@5 6783
philpem@5 6784 //! Display an image CImg<T> into a display window.
philpem@5 6785 template<typename T>
philpem@5 6786 CImgDisplay& operator<<(const CImg<T>& img) {
philpem@5 6787 return display(img);
philpem@5 6788 }
philpem@5 6789
philpem@5 6790 //! Display an image CImg<T> into a display window.
philpem@5 6791 template<typename T>
philpem@5 6792 CImgDisplay& operator<<(const CImgList<T>& list) {
philpem@5 6793 return display(list);
philpem@5 6794 }
philpem@5 6795
philpem@5 6796 //! Resize a display window with the size of an image.
philpem@5 6797 /** \param img : Input image. \p image.width and \p image.height give the new dimensions of the display window.
philpem@5 6798 \param redraw : If \p true (default), the current displayed image in the display window will
philpem@5 6799 be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window.
philpem@5 6800 **/
philpem@5 6801 template<typename T>
philpem@5 6802 CImgDisplay& resize(const CImg<T>& img, const bool redraw=true) {
philpem@5 6803 return resize(img.width,img.height,redraw);
philpem@5 6804 }
philpem@5 6805
philpem@5 6806 //! Resize a display window using the size of the given display \p disp.
philpem@5 6807 CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) {
philpem@5 6808 return resize(disp.width,disp.height,redraw);
philpem@5 6809 }
philpem@5 6810
philpem@5 6811 //! Resize a display window in its current size.
philpem@5 6812 CImgDisplay& resize(const bool redraw=true) {
philpem@5 6813 resize(window_width,window_height,redraw);
philpem@5 6814 return *this;
philpem@5 6815 }
philpem@5 6816
philpem@5 6817 //! Set fullscreen mode.
philpem@5 6818 CImgDisplay& fullscreen(const bool redraw=true) {
philpem@5 6819 if (is_empty() || is_fullscreen) return *this;
philpem@5 6820 return toggle_fullscreen(redraw);
philpem@5 6821 }
philpem@5 6822
philpem@5 6823 //! Set normal screen mode.
philpem@5 6824 CImgDisplay& normalscreen(const bool redraw=true) {
philpem@5 6825 if (is_empty() || !is_fullscreen) return *this;
philpem@5 6826 return toggle_fullscreen(redraw);
philpem@5 6827 }
philpem@5 6828
philpem@5 6829 // Inner routine used for fast resizing of buffer to display size.
philpem@5 6830 template<typename t, typename T>
philpem@5 6831 static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs,
philpem@5 6832 t *ptrd, const unsigned int wd, const unsigned int hd) {
philpem@5 6833 unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy;
philpem@5 6834 float s, curr, old;
philpem@5 6835 s = (float)ws/wd;
philpem@5 6836 poffx = offx; curr = 0; for (unsigned int x=0; x<wd; ++x) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; }
philpem@5 6837 s = (float)hs/hd;
philpem@5 6838 poffy = offy; curr = 0; for (unsigned int y=0; y<hd; ++y) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); }
philpem@5 6839 *poffy = 0;
philpem@5 6840 poffy = offy;
philpem@5 6841 {for (unsigned int y=0; y<hd; ) {
philpem@5 6842 const T *ptr = ptrs;
philpem@5 6843 poffx = offx;
philpem@5 6844 for (unsigned int x=0; x<wd; ++x) { *(ptrd++) = *ptr; ptr+=*(poffx++); }
philpem@5 6845 ++y;
philpem@5 6846 unsigned int dy=*(poffy++);
philpem@5 6847 for (;!dy && y<hd; cimg_std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), ++y, ptrd+=wd, dy=*(poffy++)) {}
philpem@5 6848 ptrs+=dy;
philpem@5 6849 }}
philpem@5 6850 delete[] offx; delete[] offy;
philpem@5 6851 }
philpem@5 6852
philpem@5 6853 //! Clear all events of the current display.
philpem@5 6854 CImgDisplay& flush() {
philpem@5 6855 cimg_std::memset((void*)buttons,0,512*sizeof(unsigned int));
philpem@5 6856 cimg_std::memset((void*)keys,0,512*sizeof(unsigned int));
philpem@5 6857 cimg_std::memset((void*)released_keys,0,512*sizeof(unsigned int));
philpem@5 6858 is_keyESC = is_keyF1 = is_keyF2 = is_keyF3 = is_keyF4 = is_keyF5 = is_keyF6 = is_keyF7 = is_keyF8 = is_keyF9 =
philpem@5 6859 is_keyF10 = is_keyF11 = is_keyF12 = is_keyPAUSE = is_key1 = is_key2 = is_key3 = is_key4 = is_key5 = is_key6 =
philpem@5 6860 is_key7 = is_key8 = is_key9 = is_key0 = is_keyBACKSPACE = is_keyINSERT = is_keyHOME = is_keyPAGEUP = is_keyTAB =
philpem@5 6861 is_keyQ = is_keyW = is_keyE = is_keyR = is_keyT = is_keyY = is_keyU = is_keyI = is_keyO = is_keyP = is_keyDELETE =
philpem@5 6862 is_keyEND = is_keyPAGEDOWN = is_keyCAPSLOCK = is_keyA = is_keyS = is_keyD = is_keyF = is_keyG = is_keyH = is_keyJ =
philpem@5 6863 is_keyK = is_keyL = is_keyENTER = is_keySHIFTLEFT = is_keyZ = is_keyX = is_keyC = is_keyV = is_keyB = is_keyN =
philpem@5 6864 is_keyM = is_keySHIFTRIGHT = is_keyARROWUP = is_keyCTRLLEFT = is_keyAPPLEFT = is_keyALT = is_keySPACE = is_keyALTGR = is_keyAPPRIGHT =
philpem@5 6865 is_keyMENU = is_keyCTRLRIGHT = is_keyARROWLEFT = is_keyARROWDOWN = is_keyARROWRIGHT = is_keyPAD0 = is_keyPAD1 = is_keyPAD2 =
philpem@5 6866 is_keyPAD3 = is_keyPAD4 = is_keyPAD5 = is_keyPAD6 = is_keyPAD7 = is_keyPAD8 = is_keyPAD9 = is_keyPADADD = is_keyPADSUB =
philpem@5 6867 is_keyPADMUL = is_keyPADDIV = false;
philpem@5 6868 is_resized = is_moved = is_event = false;
philpem@5 6869 fps_timer = fps_frames = timer = wheel = 0;
philpem@5 6870 mouse_x = mouse_y = -1;
philpem@5 6871 fps_fps = 0;
philpem@5 6872 return *this;
philpem@5 6873 }
philpem@5 6874
philpem@5 6875 // Update 'is_key' fields.
philpem@5 6876 void update_iskey(const unsigned int key, const bool pressed=true) {
philpem@5 6877 #define _cimg_iskey_case(k) if (key==cimg::key##k) is_key##k = pressed;
philpem@5 6878 _cimg_iskey_case(ESC); _cimg_iskey_case(F1); _cimg_iskey_case(F2); _cimg_iskey_case(F3);
philpem@5 6879 _cimg_iskey_case(F4); _cimg_iskey_case(F5); _cimg_iskey_case(F6); _cimg_iskey_case(F7);
philpem@5 6880 _cimg_iskey_case(F8); _cimg_iskey_case(F9); _cimg_iskey_case(F10); _cimg_iskey_case(F11);
philpem@5 6881 _cimg_iskey_case(F12); _cimg_iskey_case(PAUSE); _cimg_iskey_case(1); _cimg_iskey_case(2);
philpem@5 6882 _cimg_iskey_case(3); _cimg_iskey_case(4); _cimg_iskey_case(5); _cimg_iskey_case(6);
philpem@5 6883 _cimg_iskey_case(7); _cimg_iskey_case(8); _cimg_iskey_case(9); _cimg_iskey_case(0);
philpem@5 6884 _cimg_iskey_case(BACKSPACE); _cimg_iskey_case(INSERT); _cimg_iskey_case(HOME);
philpem@5 6885 _cimg_iskey_case(PAGEUP); _cimg_iskey_case(TAB); _cimg_iskey_case(Q); _cimg_iskey_case(W);
philpem@5 6886 _cimg_iskey_case(E); _cimg_iskey_case(R); _cimg_iskey_case(T); _cimg_iskey_case(Y);
philpem@5 6887 _cimg_iskey_case(U); _cimg_iskey_case(I); _cimg_iskey_case(O); _cimg_iskey_case(P);
philpem@5 6888 _cimg_iskey_case(DELETE); _cimg_iskey_case(END); _cimg_iskey_case(PAGEDOWN);
philpem@5 6889 _cimg_iskey_case(CAPSLOCK); _cimg_iskey_case(A); _cimg_iskey_case(S); _cimg_iskey_case(D);
philpem@5 6890 _cimg_iskey_case(F); _cimg_iskey_case(G); _cimg_iskey_case(H); _cimg_iskey_case(J);
philpem@5 6891 _cimg_iskey_case(K); _cimg_iskey_case(L); _cimg_iskey_case(ENTER);
philpem@5 6892 _cimg_iskey_case(SHIFTLEFT); _cimg_iskey_case(Z); _cimg_iskey_case(X); _cimg_iskey_case(C);
philpem@5 6893 _cimg_iskey_case(V); _cimg_iskey_case(B); _cimg_iskey_case(N); _cimg_iskey_case(M);
philpem@5 6894 _cimg_iskey_case(SHIFTRIGHT); _cimg_iskey_case(ARROWUP); _cimg_iskey_case(CTRLLEFT);
philpem@5 6895 _cimg_iskey_case(APPLEFT); _cimg_iskey_case(ALT); _cimg_iskey_case(SPACE); _cimg_iskey_case(ALTGR);
philpem@5 6896 _cimg_iskey_case(APPRIGHT); _cimg_iskey_case(MENU); _cimg_iskey_case(CTRLRIGHT);
philpem@5 6897 _cimg_iskey_case(ARROWLEFT); _cimg_iskey_case(ARROWDOWN); _cimg_iskey_case(ARROWRIGHT);
philpem@5 6898 _cimg_iskey_case(PAD0); _cimg_iskey_case(PAD1); _cimg_iskey_case(PAD2);
philpem@5 6899 _cimg_iskey_case(PAD3); _cimg_iskey_case(PAD4); _cimg_iskey_case(PAD5);
philpem@5 6900 _cimg_iskey_case(PAD6); _cimg_iskey_case(PAD7); _cimg_iskey_case(PAD8);
philpem@5 6901 _cimg_iskey_case(PAD9); _cimg_iskey_case(PADADD); _cimg_iskey_case(PADSUB);
philpem@5 6902 _cimg_iskey_case(PADMUL); _cimg_iskey_case(PADDIV);
philpem@5 6903 }
philpem@5 6904
philpem@5 6905 //! Test if any key has been pressed.
philpem@5 6906 bool is_key(const bool remove=false) {
philpem@5 6907 for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs) { if (remove) *ptrs = 0; return true; }
philpem@5 6908 return false;
philpem@5 6909 }
philpem@5 6910
philpem@5 6911 //! Test if a key has been pressed.
philpem@5 6912 bool is_key(const unsigned int key1, const bool remove) {
philpem@5 6913 for (unsigned int *ptrs=(unsigned int*)keys+512-1; ptrs>=keys; --ptrs) if (*ptrs==key1) { if (remove) *ptrs = 0; return true; }
philpem@5 6914 return false;
philpem@5 6915 }
philpem@5 6916
philpem@5 6917 //! Test if a key sequence has been typed.
philpem@5 6918 bool is_key(const unsigned int key1, const unsigned int key2, const bool remove) {
philpem@5 6919 const unsigned int seq[] = { key1, key2 };
philpem@5 6920 return is_key(seq,2,remove);
philpem@5 6921 }
philpem@5 6922
philpem@5 6923 //! Test if a key sequence has been typed.
philpem@5 6924 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove) {
philpem@5 6925 const unsigned int seq[] = { key1, key2, key3 };
philpem@5 6926 return is_key(seq,3,remove);
philpem@5 6927 }
philpem@5 6928
philpem@5 6929 //! Test if a key sequence has been typed.
philpem@5 6930 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6931 const unsigned int key4, const bool remove) {
philpem@5 6932 const unsigned int seq[] = { key1, key2, key3, key4 };
philpem@5 6933 return is_key(seq,4,remove);
philpem@5 6934 }
philpem@5 6935
philpem@5 6936 //! Test if a key sequence has been typed.
philpem@5 6937 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6938 const unsigned int key4, const unsigned int key5, const bool remove) {
philpem@5 6939 const unsigned int seq[] = { key1, key2, key3, key4, key5 };
philpem@5 6940 return is_key(seq,5,remove);
philpem@5 6941 }
philpem@5 6942
philpem@5 6943 //! Test if a key sequence has been typed.
philpem@5 6944 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6945 const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove) {
philpem@5 6946 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6 };
philpem@5 6947 return is_key(seq,6,remove);
philpem@5 6948 }
philpem@5 6949
philpem@5 6950 //! Test if a key sequence has been typed.
philpem@5 6951 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6952 const unsigned int key4, const unsigned int key5, const unsigned int key6,
philpem@5 6953 const unsigned int key7, const bool remove) {
philpem@5 6954 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7 };
philpem@5 6955 return is_key(seq,7,remove);
philpem@5 6956 }
philpem@5 6957
philpem@5 6958 //! Test if a key sequence has been typed.
philpem@5 6959 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6960 const unsigned int key4, const unsigned int key5, const unsigned int key6,
philpem@5 6961 const unsigned int key7, const unsigned int key8, const bool remove) {
philpem@5 6962 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8 };
philpem@5 6963 return is_key(seq,8,remove);
philpem@5 6964 }
philpem@5 6965
philpem@5 6966 //! Test if a key sequence has been typed.
philpem@5 6967 bool is_key(const unsigned int key1, const unsigned int key2, const unsigned int key3,
philpem@5 6968 const unsigned int key4, const unsigned int key5, const unsigned int key6,
philpem@5 6969 const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove) {
philpem@5 6970 const unsigned int seq[] = { key1, key2, key3, key4, key5, key6, key7, key8, key9 };
philpem@5 6971 return is_key(seq,9,remove);
philpem@5 6972 }
philpem@5 6973
philpem@5 6974 //! Test if a key sequence has been typed.
philpem@5 6975 bool is_key(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) {
philpem@5 6976 if (keyseq && N) {
philpem@5 6977 const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+1+512-N;
philpem@5 6978 for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) {
philpem@5 6979 if (*(pk++)==k) {
philpem@5 6980 bool res = true;
philpem@5 6981 const unsigned int *ps = ps_end, *pk2 = pk;
philpem@5 6982 for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++));
philpem@5 6983 if (res) {
philpem@5 6984 if (remove) cimg_std::memset((void*)(pk-1),0,sizeof(unsigned int)*N);
philpem@5 6985 return true;
philpem@5 6986 }
philpem@5 6987 }
philpem@5 6988 }
philpem@5 6989 }
philpem@5 6990 return false;
philpem@5 6991 }
philpem@5 6992
philpem@5 6993 // Find the good width and height of a window to display an image (internal routine).
philpem@5 6994 #define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,128,-85,false),CImgDisplay::_fitscreen(dx,dy,dz,128,-85,true)
philpem@5 6995 static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1,
philpem@5 6996 const int dmin=128, const int dmax=-85,const bool return_last=false) {
philpem@5 6997 unsigned int nw = dx + (dz>1?dz:0), nh = dy + (dz>1?dz:0);
philpem@5 6998 const unsigned int
philpem@5 6999 sw = CImgDisplay::screen_dimx(), sh = CImgDisplay::screen_dimy(),
philpem@5 7000 mw = dmin<0?(unsigned int)(sw*-dmin/100):(unsigned int)dmin,
philpem@5 7001 mh = dmin<0?(unsigned int)(sh*-dmin/100):(unsigned int)dmin,
philpem@5 7002 Mw = dmax<0?(unsigned int)(sw*-dmax/100):(unsigned int)dmax,
philpem@5 7003 Mh = dmax<0?(unsigned int)(sh*-dmax/100):(unsigned int)dmax;
philpem@5 7004 if (nw<mw) { nh = nh*mw/nw; nh+=(nh==0); nw = mw; }
philpem@5 7005 if (nh<mh) { nw = nw*mh/nh; nw+=(nw==0); nh = mh; }
philpem@5 7006 if (nw>Mw) { nh = nh*Mw/nw; nh+=(nh==0); nw = Mw; }
philpem@5 7007 if (nh>Mh) { nw = nw*Mh/nh; nw+=(nw==0); nh = Mh; }
philpem@5 7008 if (nw<mw) nw = mw;
philpem@5 7009 if (nh<mh) nh = mh;
philpem@5 7010 if (return_last) return nh;
philpem@5 7011 return nw;
philpem@5 7012 }
philpem@5 7013
philpem@5 7014 // When no display available
philpem@5 7015 //---------------------------
philpem@5 7016 #if cimg_display==0
philpem@5 7017
philpem@5 7018 //! Return the width of the screen resolution.
philpem@5 7019 static int screen_dimx() {
philpem@5 7020 return 0;
philpem@5 7021 }
philpem@5 7022
philpem@5 7023 //! Return the height of the screen resolution.
philpem@5 7024 static int screen_dimy() {
philpem@5 7025 return 0;
philpem@5 7026 }
philpem@5 7027
philpem@5 7028 //! Wait for a window event in any CImg window.
philpem@5 7029 static void wait_all() {}
philpem@5 7030
philpem@5 7031 //! In-place version of the destructor.
philpem@5 7032 CImgDisplay& assign() {
philpem@5 7033 return *this;
philpem@5 7034 }
philpem@5 7035
philpem@5 7036 //! In-place version of the previous constructor.
philpem@5 7037 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
philpem@5 7038 const unsigned int normalization_type=3,
philpem@5 7039 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7040 throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display=0)");
philpem@5 7041 const char* avoid_warning = title + dimw + dimh + normalization_type + (int)fullscreen_flag + (int)closed_flag;
philpem@5 7042 avoid_warning = 0;
philpem@5 7043 return *this;
philpem@5 7044 }
philpem@5 7045
philpem@5 7046 //! In-place version of the previous constructor.
philpem@5 7047 template<typename T>
philpem@5 7048 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
philpem@5 7049 const unsigned int normalization_type=3,
philpem@5 7050 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7051 throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
philpem@5 7052 const char* avoid_warning = title + img.width + normalization_type + (int)fullscreen_flag + (int)closed_flag;
philpem@5 7053 avoid_warning = 0;
philpem@5 7054 return assign(0,0);
philpem@5 7055 }
philpem@5 7056
philpem@5 7057 //! In-place version of the previous constructor.
philpem@5 7058 template<typename T>
philpem@5 7059 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
philpem@5 7060 const unsigned int normalization_type=3,
philpem@5 7061 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7062 throw CImgDisplayException("CImgDisplay()::assign() : Display has been required but is not available (cimg_display=0)");
philpem@5 7063 const char* avoid_warning = title + list.size + normalization_type + (int)fullscreen_flag + (int)closed_flag;
philpem@5 7064 avoid_warning = 0;
philpem@5 7065 return assign(0,0);
philpem@5 7066 }
philpem@5 7067
philpem@5 7068 //! In-place version of the previous constructor.
philpem@5 7069 CImgDisplay& assign(const CImgDisplay &disp) {
philpem@5 7070 return assign(disp.width,disp.height);
philpem@5 7071 }
philpem@5 7072
philpem@5 7073 //! Resize window.
philpem@5 7074 CImgDisplay& resize(const int width, const int height, const bool redraw=true) {
philpem@5 7075 int avoid_warning = width | height | (int)redraw;
philpem@5 7076 avoid_warning = 0;
philpem@5 7077 return *this;
philpem@5 7078 }
philpem@5 7079
philpem@5 7080 //! Toggle fullscreen mode.
philpem@5 7081 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
philpem@5 7082 bool avoid_warning = redraw;
philpem@5 7083 avoid_warning = false;
philpem@5 7084 return *this;
philpem@5 7085 }
philpem@5 7086
philpem@5 7087 //! Show a closed display.
philpem@5 7088 CImgDisplay& show() {
philpem@5 7089 return *this;
philpem@5 7090 }
philpem@5 7091
philpem@5 7092 //! Close a visible display.
philpem@5 7093 CImgDisplay& close() {
philpem@5 7094 return *this;
philpem@5 7095 }
philpem@5 7096
philpem@5 7097 //! Move window.
philpem@5 7098 CImgDisplay& move(const int posx, const int posy) {
philpem@5 7099 int avoid_warning = posx | posy;
philpem@5 7100 avoid_warning = 0;
philpem@5 7101 return *this;
philpem@5 7102 }
philpem@5 7103
philpem@5 7104 //! Show mouse pointer.
philpem@5 7105 CImgDisplay& show_mouse() {
philpem@5 7106 return *this;
philpem@5 7107 }
philpem@5 7108
philpem@5 7109 //! Hide mouse pointer.
philpem@5 7110 CImgDisplay& hide_mouse() {
philpem@5 7111 return *this;
philpem@5 7112 }
philpem@5 7113
philpem@5 7114 //! Move mouse pointer to a specific location.
philpem@5 7115 CImgDisplay& set_mouse(const int posx, const int posy) {
philpem@5 7116 int avoid_warning = posx | posy;
philpem@5 7117 avoid_warning = 0;
philpem@5 7118 return *this;
philpem@5 7119 }
philpem@5 7120
philpem@5 7121 //! Set the window title.
philpem@5 7122 CImgDisplay& set_title(const char *format, ...) {
philpem@5 7123 const char *avoid_warning = format;
philpem@5 7124 avoid_warning = 0;
philpem@5 7125 return *this;
philpem@5 7126 }
philpem@5 7127
philpem@5 7128 //! Display an image in a window.
philpem@5 7129 template<typename T>
philpem@5 7130 CImgDisplay& display(const CImg<T>& img) {
philpem@5 7131 unsigned int avoid_warning = img.width;
philpem@5 7132 avoid_warning = 0;
philpem@5 7133 return *this;
philpem@5 7134 }
philpem@5 7135
philpem@5 7136 //! Re-paint image content in window.
philpem@5 7137 CImgDisplay& paint() {
philpem@5 7138 return *this;
philpem@5 7139 }
philpem@5 7140
philpem@5 7141 //! Render image buffer into GDI native image format.
philpem@5 7142 template<typename T>
philpem@5 7143 CImgDisplay& render(const CImg<T>& img) {
philpem@5 7144 unsigned int avoid_warning = img.width;
philpem@5 7145 avoid_warning = 0;
philpem@5 7146 return *this;
philpem@5 7147 }
philpem@5 7148
philpem@5 7149 //! Take a snapshot of the display in the specified image.
philpem@5 7150 template<typename T>
philpem@5 7151 const CImgDisplay& snapshot(CImg<T>& img) const {
philpem@5 7152 img.assign(width,height,1,3,0);
philpem@5 7153 return *this;
philpem@5 7154 }
philpem@5 7155
philpem@5 7156 // X11-based display
philpem@5 7157 //-------------------
philpem@5 7158 #elif cimg_display==1
philpem@5 7159 Atom wm_delete_window, wm_delete_protocol;
philpem@5 7160 Window window, background_window;
philpem@5 7161 Colormap colormap;
philpem@5 7162 XImage *image;
philpem@5 7163 void *data;
philpem@5 7164 #ifdef cimg_use_xshm
philpem@5 7165 XShmSegmentInfo *shminfo;
philpem@5 7166 #endif
philpem@5 7167
philpem@5 7168 static int screen_dimx() {
philpem@5 7169 int res = 0;
philpem@5 7170 if (!cimg::X11attr().display) {
philpem@5 7171 Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
philpem@5 7172 if (!disp)
philpem@5 7173 throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display.");
philpem@5 7174 res = DisplayWidth(disp,DefaultScreen(disp));
philpem@5 7175 XCloseDisplay(disp);
philpem@5 7176 } else {
philpem@5 7177 #ifdef cimg_use_xrandr
philpem@5 7178 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
philpem@5 7179 res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width;
philpem@5 7180 else
philpem@5 7181 #endif
philpem@5 7182 res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
philpem@5 7183 }
philpem@5 7184 return res;
philpem@5 7185 }
philpem@5 7186
philpem@5 7187 static int screen_dimy() {
philpem@5 7188 int res = 0;
philpem@5 7189 if (!cimg::X11attr().display) {
philpem@5 7190 Display *disp = XOpenDisplay((cimg_std::getenv("DISPLAY") ? cimg_std::getenv("DISPLAY") : ":0.0"));
philpem@5 7191 if (!disp)
philpem@5 7192 throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display.");
philpem@5 7193 res = DisplayHeight(disp,DefaultScreen(disp));
philpem@5 7194 XCloseDisplay(disp);
philpem@5 7195 } else {
philpem@5 7196 #ifdef cimg_use_xrandr
philpem@5 7197 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution)
philpem@5 7198 res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height;
philpem@5 7199 else
philpem@5 7200 #endif
philpem@5 7201 res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
philpem@5 7202 }
philpem@5 7203 return res;
philpem@5 7204 }
philpem@5 7205
philpem@5 7206 static void wait_all() {
philpem@5 7207 if (cimg::X11attr().display) {
philpem@5 7208 XLockDisplay(cimg::X11attr().display);
philpem@5 7209 bool flag = true;
philpem@5 7210 XEvent event;
philpem@5 7211 while (flag) {
philpem@5 7212 XNextEvent(cimg::X11attr().display, &event);
philpem@5 7213 for (unsigned int i = 0; i<cimg::X11attr().nb_wins; ++i)
philpem@5 7214 if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window) {
philpem@5 7215 cimg::X11attr().wins[i]->_handle_events(&event);
philpem@5 7216 if (cimg::X11attr().wins[i]->is_event) flag = false;
philpem@5 7217 }
philpem@5 7218 }
philpem@5 7219 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7220 }
philpem@5 7221 }
philpem@5 7222
philpem@5 7223 void _handle_events(const XEvent *const pevent) {
philpem@5 7224 XEvent event = *pevent;
philpem@5 7225 switch (event.type) {
philpem@5 7226 case ClientMessage : {
philpem@5 7227 if ((int)event.xclient.message_type==(int)wm_delete_protocol &&
philpem@5 7228 (int)event.xclient.data.l[0]==(int)wm_delete_window) {
philpem@5 7229 XUnmapWindow(cimg::X11attr().display,window);
philpem@5 7230 mouse_x = mouse_y = -1;
philpem@5 7231 if (button) { cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button = 0; }
philpem@5 7232 if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
philpem@5 7233 if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
philpem@5 7234 is_closed = is_event = true;
philpem@5 7235 }
philpem@5 7236 } break;
philpem@5 7237 case ConfigureNotify : {
philpem@5 7238 while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)) {}
philpem@5 7239 const unsigned int
philpem@5 7240 nw = event.xconfigure.width,
philpem@5 7241 nh = event.xconfigure.height;
philpem@5 7242 const int
philpem@5 7243 nx = event.xconfigure.x,
philpem@5 7244 ny = event.xconfigure.y;
philpem@5 7245 if (nw && nh && (nw!=window_width || nh!=window_height)) {
philpem@5 7246 window_width = nw;
philpem@5 7247 window_height = nh;
philpem@5 7248 mouse_x = mouse_y = -1;
philpem@5 7249 XResizeWindow(cimg::X11attr().display,window,window_width,window_height);
philpem@5 7250 is_resized = is_event = true;
philpem@5 7251 }
philpem@5 7252 if (nx!=window_x || ny!=window_y) {
philpem@5 7253 window_x = nx;
philpem@5 7254 window_y = ny;
philpem@5 7255 is_moved = is_event = true;
philpem@5 7256 }
philpem@5 7257 } break;
philpem@5 7258 case Expose : {
philpem@5 7259 while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)) {}
philpem@5 7260 _paint(false);
philpem@5 7261 if (is_fullscreen) {
philpem@5 7262 XWindowAttributes attr;
philpem@5 7263 XGetWindowAttributes(cimg::X11attr().display, window, &attr);
philpem@5 7264 while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
philpem@5 7265 XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime);
philpem@5 7266 }
philpem@5 7267 } break;
philpem@5 7268 case ButtonPress : {
philpem@5 7269 do {
philpem@5 7270 mouse_x = event.xmotion.x;
philpem@5 7271 mouse_y = event.xmotion.y;
philpem@5 7272 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
philpem@5 7273 switch (event.xbutton.button) {
philpem@5 7274 case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=1; is_event = true; break;
philpem@5 7275 case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=4; is_event = true; break;
philpem@5 7276 case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button|=2; is_event = true; break;
philpem@5 7277 }
philpem@5 7278 } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event));
philpem@5 7279 } break;
philpem@5 7280 case ButtonRelease : {
philpem@5 7281 do {
philpem@5 7282 mouse_x = event.xmotion.x;
philpem@5 7283 mouse_y = event.xmotion.y;
philpem@5 7284 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
philpem@5 7285 switch (event.xbutton.button) {
philpem@5 7286 case 1 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~1U; is_event = true; break;
philpem@5 7287 case 2 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~4U; is_event = true; break;
philpem@5 7288 case 3 : cimg_std::memmove((void*)(buttons+1),(void*)buttons,512-1); button&=~2U; is_event = true; break;
philpem@5 7289 case 4 : ++wheel; is_event = true; break;
philpem@5 7290 case 5 : --wheel; is_event = true; break;
philpem@5 7291 }
philpem@5 7292 } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event));
philpem@5 7293 } break;
philpem@5 7294 case KeyPress : {
philpem@5 7295 char tmp;
philpem@5 7296 KeySym ksym;
philpem@5 7297 XLookupString(&event.xkey,&tmp,1,&ksym,0);
philpem@5 7298 update_iskey((unsigned int)ksym,true);
philpem@5 7299 if (key) cimg_std::memmove((void*)(keys+1),(void*)keys,512-1);
philpem@5 7300 key = (unsigned int)ksym;
philpem@5 7301 if (released_key) { cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1); released_key = 0; }
philpem@5 7302 is_event = true;
philpem@5 7303 } break;
philpem@5 7304 case KeyRelease : {
philpem@5 7305 char tmp;
philpem@5 7306 KeySym ksym;
philpem@5 7307 XLookupString(&event.xkey,&tmp,1,&ksym,0);
philpem@5 7308 update_iskey((unsigned int)ksym,false);
philpem@5 7309 if (key) { cimg_std::memmove((void*)(keys+1),(void*)keys,512-1); key = 0; }
philpem@5 7310 if (released_key) cimg_std::memmove((void*)(released_keys+1),(void*)released_keys,512-1);
philpem@5 7311 released_key = (unsigned int)ksym;
philpem@5 7312 is_event = true;
philpem@5 7313 } break;
philpem@5 7314 case EnterNotify: {
philpem@5 7315 while (XCheckWindowEvent(cimg::X11attr().display,window,EnterWindowMask,&event)) {}
philpem@5 7316 mouse_x = event.xmotion.x;
philpem@5 7317 mouse_y = event.xmotion.y;
philpem@5 7318 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
philpem@5 7319 } break;
philpem@5 7320 case LeaveNotify : {
philpem@5 7321 while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)) {}
philpem@5 7322 mouse_x = mouse_y =-1;
philpem@5 7323 is_event = true;
philpem@5 7324 } break;
philpem@5 7325 case MotionNotify : {
philpem@5 7326 while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)) {}
philpem@5 7327 mouse_x = event.xmotion.x;
philpem@5 7328 mouse_y = event.xmotion.y;
philpem@5 7329 if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1;
philpem@5 7330 is_event = true;
philpem@5 7331 } break;
philpem@5 7332 }
philpem@5 7333 }
philpem@5 7334
philpem@5 7335 static void* _events_thread(void *arg) {
philpem@5 7336 arg = 0;
philpem@5 7337 XEvent event;
philpem@5 7338 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
philpem@5 7339 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
philpem@5 7340 for (;;) {
philpem@5 7341 XLockDisplay(cimg::X11attr().display);
philpem@5 7342 bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event);
philpem@5 7343 if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display,
philpem@5 7344 ExposureMask|StructureNotifyMask|ButtonPressMask|
philpem@5 7345 KeyPressMask|PointerMotionMask|EnterWindowMask|LeaveWindowMask|
philpem@5 7346 ButtonReleaseMask|KeyReleaseMask,&event);
philpem@5 7347 if (event_flag) {
philpem@5 7348 for (unsigned int i=0; i<cimg::X11attr().nb_wins; ++i)
philpem@5 7349 if (!cimg::X11attr().wins[i]->is_closed && event.xany.window==cimg::X11attr().wins[i]->window)
philpem@5 7350 cimg::X11attr().wins[i]->_handle_events(&event);
philpem@5 7351 }
philpem@5 7352 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7353 pthread_testcancel();
philpem@5 7354 cimg::sleep(7);
philpem@5 7355 }
philpem@5 7356 return 0;
philpem@5 7357 }
philpem@5 7358
philpem@5 7359 void _set_colormap(Colormap& colormap, const unsigned int dim) {
philpem@5 7360 XColor palette[256];
philpem@5 7361 switch (dim) {
philpem@5 7362 case 1 : { // palette for greyscale images
philpem@5 7363 for (unsigned int index=0; index<256; ++index) {
philpem@5 7364 palette[index].pixel = index;
philpem@5 7365 palette[index].red = palette[index].green = palette[index].blue = (unsigned short)(index<<8);
philpem@5 7366 palette[index].flags = DoRed | DoGreen | DoBlue;
philpem@5 7367 }
philpem@5 7368 } break;
philpem@5 7369 case 2 : { // palette for RG images
philpem@5 7370 for (unsigned int index=0, r=8; r<256; r+=16)
philpem@5 7371 for (unsigned int g=8; g<256; g+=16) {
philpem@5 7372 palette[index].pixel = index;
philpem@5 7373 palette[index].red = palette[index].blue = (unsigned short)(r<<8);
philpem@5 7374 palette[index].green = (unsigned short)(g<<8);
philpem@5 7375 palette[index++].flags = DoRed | DoGreen | DoBlue;
philpem@5 7376 }
philpem@5 7377 } break;
philpem@5 7378 default : { // palette for RGB images
philpem@5 7379 for (unsigned int index=0, r=16; r<256; r+=32)
philpem@5 7380 for (unsigned int g=16; g<256; g+=32)
philpem@5 7381 for (unsigned int b=32; b<256; b+=64) {
philpem@5 7382 palette[index].pixel = index;
philpem@5 7383 palette[index].red = (unsigned short)(r<<8);
philpem@5 7384 palette[index].green = (unsigned short)(g<<8);
philpem@5 7385 palette[index].blue = (unsigned short)(b<<8);
philpem@5 7386 palette[index++].flags = DoRed | DoGreen | DoBlue;
philpem@5 7387 }
philpem@5 7388 }
philpem@5 7389 }
philpem@5 7390 XStoreColors(cimg::X11attr().display,colormap,palette,256);
philpem@5 7391 }
philpem@5 7392
philpem@5 7393 void _map_window() {
philpem@5 7394 XWindowAttributes attr;
philpem@5 7395 XEvent event;
philpem@5 7396 bool exposed = false, mapped = false;
philpem@5 7397 XMapRaised(cimg::X11attr().display,window);
philpem@5 7398 XSync(cimg::X11attr().display,False);
philpem@5 7399 do {
philpem@5 7400 XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event);
philpem@5 7401 switch (event.type) {
philpem@5 7402 case MapNotify : mapped = true; break;
philpem@5 7403 case Expose : exposed = true; break;
philpem@5 7404 default : XSync(cimg::X11attr().display, False); cimg::sleep(10);
philpem@5 7405 }
philpem@5 7406 } while (!(exposed && mapped));
philpem@5 7407 do {
philpem@5 7408 XGetWindowAttributes(cimg::X11attr().display, window, &attr);
philpem@5 7409 if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); }
philpem@5 7410 } while (attr.map_state != IsViewable);
philpem@5 7411 window_x = attr.x;
philpem@5 7412 window_y = attr.y;
philpem@5 7413 }
philpem@5 7414
philpem@5 7415 void _paint(const bool wait_expose=true) {
philpem@5 7416 if (!is_closed) {
philpem@5 7417 if (wait_expose) {
philpem@5 7418 static XEvent event;
philpem@5 7419 event.xexpose.type = Expose;
philpem@5 7420 event.xexpose.serial = 0;
philpem@5 7421 event.xexpose.send_event = True;
philpem@5 7422 event.xexpose.display = cimg::X11attr().display;
philpem@5 7423 event.xexpose.window = window;
philpem@5 7424 event.xexpose.x = 0;
philpem@5 7425 event.xexpose.y = 0;
philpem@5 7426 event.xexpose.width = dimx();
philpem@5 7427 event.xexpose.height = dimy();
philpem@5 7428 event.xexpose.count = 0;
philpem@5 7429 XSendEvent(cimg::X11attr().display, window, False, 0, &event);
philpem@5 7430 } else {
philpem@5 7431 #ifdef cimg_use_xshm
philpem@5 7432 if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False);
philpem@5 7433 else
philpem@5 7434 #endif
philpem@5 7435 XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height);
philpem@5 7436 XSync(cimg::X11attr().display, False);
philpem@5 7437 }
philpem@5 7438 }
philpem@5 7439 }
philpem@5 7440
philpem@5 7441 template<typename T>
philpem@5 7442 void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) {
philpem@5 7443 foo = 0;
philpem@5 7444 #ifdef cimg_use_xshm
philpem@5 7445 if (shminfo) {
philpem@5 7446 XShmSegmentInfo *nshminfo = new XShmSegmentInfo;
philpem@5 7447 XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7448 cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy);
philpem@5 7449 if (!nimage) {
philpem@5 7450 delete nshminfo;
philpem@5 7451 return;
philpem@5 7452 } else {
philpem@5 7453 nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777);
philpem@5 7454 if (nshminfo->shmid==-1) {
philpem@5 7455 XDestroyImage(nimage);
philpem@5 7456 delete nshminfo;
philpem@5 7457 return;
philpem@5 7458 } else {
philpem@5 7459 nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0);
philpem@5 7460 if (nshminfo->shmaddr==(char*)-1) {
philpem@5 7461 shmctl(nshminfo->shmid,IPC_RMID,0);
philpem@5 7462 XDestroyImage(nimage);
philpem@5 7463 delete nshminfo;
philpem@5 7464 return;
philpem@5 7465 } else {
philpem@5 7466 nshminfo->readOnly = False;
philpem@5 7467 cimg::X11attr().shm_enabled = true;
philpem@5 7468 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
philpem@5 7469 XShmAttach(cimg::X11attr().display, nshminfo);
philpem@5 7470 XSync(cimg::X11attr().display, False);
philpem@5 7471 XSetErrorHandler(oldXErrorHandler);
philpem@5 7472 if (!cimg::X11attr().shm_enabled) {
philpem@5 7473 shmdt(nshminfo->shmaddr);
philpem@5 7474 shmctl(nshminfo->shmid,IPC_RMID,0);
philpem@5 7475 XDestroyImage(nimage);
philpem@5 7476 delete nshminfo;
philpem@5 7477 return;
philpem@5 7478 } else {
philpem@5 7479 T *const ndata = (T*)nimage->data;
philpem@5 7480 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
philpem@5 7481 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
philpem@5 7482 XShmDetach(cimg::X11attr().display, shminfo);
philpem@5 7483 XDestroyImage(image);
philpem@5 7484 shmdt(shminfo->shmaddr);
philpem@5 7485 shmctl(shminfo->shmid,IPC_RMID,0);
philpem@5 7486 delete shminfo;
philpem@5 7487 shminfo = nshminfo;
philpem@5 7488 image = nimage;
philpem@5 7489 data = (void*)ndata;
philpem@5 7490 }
philpem@5 7491 }
philpem@5 7492 }
philpem@5 7493 }
philpem@5 7494 } else
philpem@5 7495 #endif
philpem@5 7496 {
philpem@5 7497 T *ndata = (T*)cimg_std::malloc(ndimx*ndimy*sizeof(T));
philpem@5 7498 if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy);
philpem@5 7499 else cimg_std::memset(ndata,0,sizeof(T)*ndimx*ndimy);
philpem@5 7500 data = (void*)ndata;
philpem@5 7501 XDestroyImage(image);
philpem@5 7502 image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7503 cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0);
philpem@5 7504 }
philpem@5 7505 }
philpem@5 7506
philpem@5 7507 void _init_fullscreen() {
philpem@5 7508 background_window = 0;
philpem@5 7509 if (is_fullscreen && !is_closed) {
philpem@5 7510 #ifdef cimg_use_xrandr
philpem@5 7511 int foo;
philpem@5 7512 if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) {
philpem@5 7513 XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation);
philpem@5 7514 if (!cimg::X11attr().resolutions) {
philpem@5 7515 cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo);
philpem@5 7516 cimg::X11attr().nb_resolutions = (unsigned int)foo;
philpem@5 7517 }
philpem@5 7518 if (cimg::X11attr().resolutions) {
philpem@5 7519 cimg::X11attr().curr_resolution = 0;
philpem@5 7520 for (unsigned int i=0; i<cimg::X11attr().nb_resolutions; ++i) {
philpem@5 7521 const unsigned int
philpem@5 7522 nw = (unsigned int)(cimg::X11attr().resolutions[i].width),
philpem@5 7523 nh = (unsigned int)(cimg::X11attr().resolutions[i].height);
philpem@5 7524 if (nw>=width && nh>=height &&
philpem@5 7525 nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) &&
philpem@5 7526 nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height))
philpem@5 7527 cimg::X11attr().curr_resolution = i;
philpem@5 7528 }
philpem@5 7529 if (cimg::X11attr().curr_resolution>0) {
philpem@5 7530 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
philpem@5 7531 XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
philpem@5 7532 cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime);
philpem@5 7533 XRRFreeScreenConfigInfo(config);
philpem@5 7534 XSync(cimg::X11attr().display, False);
philpem@5 7535 }
philpem@5 7536 }
philpem@5 7537 }
philpem@5 7538 if (!cimg::X11attr().resolutions)
philpem@5 7539 cimg::warn("CImgDisplay::_create_window() : Xrandr extension is not supported by the X server.");
philpem@5 7540 #endif
philpem@5 7541 const unsigned int sx = screen_dimx(), sy = screen_dimy();
philpem@5 7542 XSetWindowAttributes winattr;
philpem@5 7543 winattr.override_redirect = True;
philpem@5 7544 if (sx!=width || sy!=height) {
philpem@5 7545 background_window = XCreateWindow(cimg::X11attr().display,
philpem@5 7546 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0,
philpem@5 7547 sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
philpem@5 7548 const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
philpem@5 7549 void *background_data = cimg_std::malloc(bufsize);
philpem@5 7550 cimg_std::memset(background_data,0,bufsize);
philpem@5 7551 XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7552 cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0);
philpem@5 7553 XEvent event;
philpem@5 7554 XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask);
philpem@5 7555 XMapRaised(cimg::X11attr().display,background_window);
philpem@5 7556 do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event);
philpem@5 7557 while (event.type!=MapNotify);
philpem@5 7558 #ifdef cimg_use_xshm
philpem@5 7559 if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False);
philpem@5 7560 else
philpem@5 7561 #endif
philpem@5 7562 XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy);
philpem@5 7563 XWindowAttributes attr;
philpem@5 7564 XGetWindowAttributes(cimg::X11attr().display, background_window, &attr);
philpem@5 7565 while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False);
philpem@5 7566 XDestroyImage(background_image);
philpem@5 7567 }
philpem@5 7568 }
philpem@5 7569 }
philpem@5 7570
philpem@5 7571 void _desinit_fullscreen() {
philpem@5 7572 if (is_fullscreen) {
philpem@5 7573 XUngrabKeyboard(cimg::X11attr().display,CurrentTime);
philpem@5 7574 #ifdef cimg_use_xrandr
philpem@5 7575 if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) {
philpem@5 7576 XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display));
philpem@5 7577 XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display),
philpem@5 7578 0, cimg::X11attr().curr_rotation, CurrentTime);
philpem@5 7579 XRRFreeScreenConfigInfo(config);
philpem@5 7580 XSync(cimg::X11attr().display, False);
philpem@5 7581 cimg::X11attr().curr_resolution = 0;
philpem@5 7582 }
philpem@5 7583 #endif
philpem@5 7584 if (background_window) XDestroyWindow(cimg::X11attr().display,background_window);
philpem@5 7585 background_window = 0;
philpem@5 7586 is_fullscreen = false;
philpem@5 7587 }
philpem@5 7588 }
philpem@5 7589
philpem@5 7590 static int _assign_xshm(Display *dpy, XErrorEvent *error) {
philpem@5 7591 dpy = 0; error = 0;
philpem@5 7592 cimg::X11attr().shm_enabled = false;
philpem@5 7593 return 0;
philpem@5 7594 }
philpem@5 7595
philpem@5 7596 void _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
philpem@5 7597 const unsigned int normalization_type=3,
philpem@5 7598 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7599
philpem@5 7600 // Allocate space for window title
philpem@5 7601 const int s = cimg::strlen(ptitle)+1;
philpem@5 7602 char *tmp_title = s?new char[s]:0;
philpem@5 7603 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
philpem@5 7604
philpem@5 7605 // Destroy previous display window if existing
philpem@5 7606 if (!is_empty()) assign();
philpem@5 7607
philpem@5 7608 // Open X11 display if necessary.
philpem@5 7609 if (!cimg::X11attr().display) {
philpem@5 7610 static bool xinit_threads = false;
philpem@5 7611 if (!xinit_threads) { XInitThreads(); xinit_threads = true; }
philpem@5 7612 cimg::X11attr().nb_wins = 0;
philpem@5 7613 cimg::X11attr().display = XOpenDisplay((cimg_std::getenv("DISPLAY")?cimg_std::getenv("DISPLAY"):":0.0"));
philpem@5 7614 if (!cimg::X11attr().display)
philpem@5 7615 throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display");
philpem@5 7616 cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display));
philpem@5 7617 if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32)
philpem@5 7618 throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported "
philpem@5 7619 "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits);
philpem@5 7620 cimg::X11attr().gc = new GC;
philpem@5 7621 *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
philpem@5 7622 Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display));
philpem@5 7623 XVisualInfo vtemplate;
philpem@5 7624 vtemplate.visualid = XVisualIDFromVisual(visual);
philpem@5 7625 int nb_visuals;
philpem@5 7626 XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals);
philpem@5 7627 if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true;
philpem@5 7628 cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display);
philpem@5 7629 XFree(vinfo);
philpem@5 7630 XLockDisplay(cimg::X11attr().display);
philpem@5 7631 cimg::X11attr().event_thread = new pthread_t;
philpem@5 7632 pthread_create(cimg::X11attr().event_thread,0,_events_thread,0);
philpem@5 7633 } else XLockDisplay(cimg::X11attr().display);
philpem@5 7634
philpem@5 7635 // Set display variables
philpem@5 7636 width = cimg::min(dimw,(unsigned int)screen_dimx());
philpem@5 7637 height = cimg::min(dimh,(unsigned int)screen_dimy());
philpem@5 7638 normalization = normalization_type<4?normalization_type:3;
philpem@5 7639 is_fullscreen = fullscreen_flag;
philpem@5 7640 window_x = window_y = 0;
philpem@5 7641 is_closed = closed_flag;
philpem@5 7642 title = tmp_title;
philpem@5 7643 flush();
philpem@5 7644
philpem@5 7645 // Create X11 window and palette (if 8bits display)
philpem@5 7646 if (is_fullscreen) {
philpem@5 7647 if (!is_closed) _init_fullscreen();
philpem@5 7648 const unsigned int sx = screen_dimx(), sy = screen_dimy();
philpem@5 7649 XSetWindowAttributes winattr;
philpem@5 7650 winattr.override_redirect = True;
philpem@5 7651 window = XCreateWindow(cimg::X11attr().display,
philpem@5 7652 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7653 (sx-width)/2,(sy-height)/2,
philpem@5 7654 width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr);
philpem@5 7655 } else
philpem@5 7656 window = XCreateSimpleWindow(cimg::X11attr().display,
philpem@5 7657 RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7658 0,0,width,height,2,0,0x0L);
philpem@5 7659 XStoreName(cimg::X11attr().display,window,title?title:" ");
philpem@5 7660 if (cimg::X11attr().nb_bits==8) {
philpem@5 7661 colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display,
philpem@5 7662 DefaultScreen(cimg::X11attr().display)),AllocAll);
philpem@5 7663 _set_colormap(colormap,3);
philpem@5 7664 XSetWindowColormap(cimg::X11attr().display,window,colormap);
philpem@5 7665 }
philpem@5 7666 window_width = width;
philpem@5 7667 window_height = height;
philpem@5 7668
philpem@5 7669 // Create XImage
philpem@5 7670 const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
philpem@5 7671 #ifdef cimg_use_xshm
philpem@5 7672 shminfo = 0;
philpem@5 7673 if (XShmQueryExtension(cimg::X11attr().display)) {
philpem@5 7674 shminfo = new XShmSegmentInfo;
philpem@5 7675 image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7676 cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height);
philpem@5 7677 if (!image) {
philpem@5 7678 delete shminfo;
philpem@5 7679 shminfo = 0;
philpem@5 7680 } else {
philpem@5 7681 shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777);
philpem@5 7682 if (shminfo->shmid==-1) {
philpem@5 7683 XDestroyImage(image);
philpem@5 7684 delete shminfo;
philpem@5 7685 shminfo = 0;
philpem@5 7686 } else {
philpem@5 7687 shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0));
philpem@5 7688 if (shminfo->shmaddr==(char*)-1) {
philpem@5 7689 shmctl(shminfo->shmid,IPC_RMID,0);
philpem@5 7690 XDestroyImage(image);
philpem@5 7691 delete shminfo;
philpem@5 7692 shminfo = 0;
philpem@5 7693 } else {
philpem@5 7694 shminfo->readOnly = False;
philpem@5 7695 cimg::X11attr().shm_enabled = true;
philpem@5 7696 XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm);
philpem@5 7697 XShmAttach(cimg::X11attr().display, shminfo);
philpem@5 7698 XSync(cimg::X11attr().display, False);
philpem@5 7699 XSetErrorHandler(oldXErrorHandler);
philpem@5 7700 if (!cimg::X11attr().shm_enabled) {
philpem@5 7701 shmdt(shminfo->shmaddr);
philpem@5 7702 shmctl(shminfo->shmid,IPC_RMID,0);
philpem@5 7703 XDestroyImage(image);
philpem@5 7704 delete shminfo;
philpem@5 7705 shminfo = 0;
philpem@5 7706 }
philpem@5 7707 }
philpem@5 7708 }
philpem@5 7709 }
philpem@5 7710 }
philpem@5 7711 if (!shminfo)
philpem@5 7712 #endif
philpem@5 7713 {
philpem@5 7714 data = cimg_std::malloc(bufsize);
philpem@5 7715 image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),
philpem@5 7716 cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0);
philpem@5 7717 }
philpem@5 7718
philpem@5 7719 wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False);
philpem@5 7720 wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False);
philpem@5 7721 XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1);
philpem@5 7722 XSelectInput(cimg::X11attr().display,window,
philpem@5 7723 ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask |
philpem@5 7724 EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask);
philpem@5 7725 if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
philpem@5 7726 cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this;
philpem@5 7727 if (!is_closed) _map_window(); else { window_x = window_y = cimg::type<int>::min(); }
philpem@5 7728 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7729 }
philpem@5 7730
philpem@5 7731 CImgDisplay& assign() {
philpem@5 7732 if (is_empty()) return *this;
philpem@5 7733 XLockDisplay(cimg::X11attr().display);
philpem@5 7734
philpem@5 7735 // Remove display window from event thread list.
philpem@5 7736 unsigned int i;
philpem@5 7737 for (i = 0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; ++i) {}
philpem@5 7738 for (; i<cimg::X11attr().nb_wins-1; ++i) cimg::X11attr().wins[i] = cimg::X11attr().wins[i+1];
philpem@5 7739 --cimg::X11attr().nb_wins;
philpem@5 7740
philpem@5 7741 // Destroy window, image, colormap and title.
philpem@5 7742 if (is_fullscreen && !is_closed) _desinit_fullscreen();
philpem@5 7743 XDestroyWindow(cimg::X11attr().display,window);
philpem@5 7744 window = 0;
philpem@5 7745 #ifdef cimg_use_xshm
philpem@5 7746 if (shminfo) {
philpem@5 7747 XShmDetach(cimg::X11attr().display, shminfo);
philpem@5 7748 XDestroyImage(image);
philpem@5 7749 shmdt(shminfo->shmaddr);
philpem@5 7750 shmctl(shminfo->shmid,IPC_RMID,0);
philpem@5 7751 delete shminfo;
philpem@5 7752 shminfo = 0;
philpem@5 7753 } else
philpem@5 7754 #endif
philpem@5 7755 XDestroyImage(image);
philpem@5 7756 data = 0; image = 0;
philpem@5 7757 if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap);
philpem@5 7758 colormap = 0;
philpem@5 7759 XSync(cimg::X11attr().display, False);
philpem@5 7760
philpem@5 7761 // Reset display variables
philpem@5 7762 if (title) delete[] title;
philpem@5 7763 width = height = normalization = window_width = window_height = 0;
philpem@5 7764 window_x = window_y = 0;
philpem@5 7765 is_fullscreen = false;
philpem@5 7766 is_closed = true;
philpem@5 7767 min = max = 0;
philpem@5 7768 title = 0;
philpem@5 7769 flush();
philpem@5 7770
philpem@5 7771 // End event thread and close display if necessary
philpem@5 7772 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7773
philpem@5 7774 /* The code below was used to close the X11 display when not used anymore,
philpem@5 7775 unfortunately, since the latest Xorg versions, it randomely hangs, so
philpem@5 7776 I prefer to remove it. A fix would be needed anyway.
philpem@5 7777
philpem@5 7778 if (!cimg::X11attr().nb_wins) {
philpem@5 7779 // Kill event thread
philpem@5 7780 pthread_cancel(*cimg::X11attr().event_thread);
philpem@5 7781 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7782 pthread_join(*cimg::X11attr().event_thread,0);
philpem@5 7783 delete cimg::X11attr().event_thread;
philpem@5 7784 cimg::X11attr().event_thread = 0;
philpem@5 7785 XCloseDisplay(cimg::X11attr().display);
philpem@5 7786 cimg::X11attr().display = 0;
philpem@5 7787 delete cimg::X11attr().gc;
philpem@5 7788 cimg::X11attr().gc = 0;
philpem@5 7789 } else XUnlockDisplay(cimg::X11attr().display);
philpem@5 7790 */
philpem@5 7791 return *this;
philpem@5 7792 }
philpem@5 7793
philpem@5 7794 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
philpem@5 7795 const unsigned int normalization_type=3,
philpem@5 7796 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7797 if (!dimw || !dimh) return assign();
philpem@5 7798 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 7799 min = max = 0;
philpem@5 7800 cimg_std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
philpem@5 7801 (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height);
philpem@5 7802 return paint();
philpem@5 7803 }
philpem@5 7804
philpem@5 7805 template<typename T>
philpem@5 7806 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
philpem@5 7807 const unsigned int normalization_type=3,
philpem@5 7808 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7809 if (!img) return assign();
philpem@5 7810 CImg<T> tmp;
philpem@5 7811 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 7812 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 7813 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 7814 return render(nimg).paint();
philpem@5 7815 }
philpem@5 7816
philpem@5 7817 template<typename T>
philpem@5 7818 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
philpem@5 7819 const unsigned int normalization_type=3,
philpem@5 7820 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 7821 if (!list) return assign();
philpem@5 7822 CImg<T> tmp;
philpem@5 7823 const CImg<T> img = list.get_append('x','p'),
philpem@5 7824 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 7825 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 7826 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 7827 return render(nimg).paint();
philpem@5 7828 }
philpem@5 7829
philpem@5 7830 CImgDisplay& assign(const CImgDisplay& win) {
philpem@5 7831 if (!win) return assign();
philpem@5 7832 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
philpem@5 7833 cimg_std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char):
philpem@5 7834 cimg::X11attr().nb_bits==16?sizeof(unsigned short):
philpem@5 7835 sizeof(unsigned int))*width*height);
philpem@5 7836 return paint();
philpem@5 7837 }
philpem@5 7838
philpem@5 7839 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
philpem@5 7840 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
philpem@5 7841 if (is_empty()) return assign(nwidth,nheight);
philpem@5 7842 const unsigned int
philpem@5 7843 tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
philpem@5 7844 tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
philpem@5 7845 dimx = tmpdimx?tmpdimx:1,
philpem@5 7846 dimy = tmpdimy?tmpdimy:1;
philpem@5 7847 XLockDisplay(cimg::X11attr().display);
philpem@5 7848 if (window_width!=dimx || window_height!=dimy) XResizeWindow(cimg::X11attr().display,window,dimx,dimy);
philpem@5 7849 if (width!=dimx || height!=dimy) switch (cimg::X11attr().nb_bits) {
philpem@5 7850 case 8 : { unsigned char foo = 0; _resize(foo,dimx,dimy,redraw); } break;
philpem@5 7851 case 16 : { unsigned short foo = 0; _resize(foo,dimx,dimy,redraw); } break;
philpem@5 7852 default : { unsigned int foo = 0; _resize(foo,dimx,dimy,redraw); }
philpem@5 7853 }
philpem@5 7854 window_width = width = dimx; window_height = height = dimy;
philpem@5 7855 is_resized = false;
philpem@5 7856 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7857 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
philpem@5 7858 if (redraw) return paint();
philpem@5 7859 return *this;
philpem@5 7860 }
philpem@5 7861
philpem@5 7862 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
philpem@5 7863 if (is_empty()) return *this;
philpem@5 7864 if (redraw) {
philpem@5 7865 const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4));
philpem@5 7866 void *odata = cimg_std::malloc(bufsize);
philpem@5 7867 cimg_std::memcpy(odata,data,bufsize);
philpem@5 7868 assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 7869 cimg_std::memcpy(data,odata,bufsize);
philpem@5 7870 cimg_std::free(odata);
philpem@5 7871 return paint(false);
philpem@5 7872 }
philpem@5 7873 return assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 7874 }
philpem@5 7875
philpem@5 7876 CImgDisplay& show() {
philpem@5 7877 if (!is_empty() && is_closed) {
philpem@5 7878 XLockDisplay(cimg::X11attr().display);
philpem@5 7879 if (is_fullscreen) _init_fullscreen();
philpem@5 7880 _map_window();
philpem@5 7881 is_closed = false;
philpem@5 7882 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7883 return paint();
philpem@5 7884 }
philpem@5 7885 return *this;
philpem@5 7886 }
philpem@5 7887
philpem@5 7888 CImgDisplay& close() {
philpem@5 7889 if (!is_empty() && !is_closed) {
philpem@5 7890 XLockDisplay(cimg::X11attr().display);
philpem@5 7891 if (is_fullscreen) _desinit_fullscreen();
philpem@5 7892 XUnmapWindow(cimg::X11attr().display,window);
philpem@5 7893 window_x = window_y = -1;
philpem@5 7894 is_closed = true;
philpem@5 7895 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7896 }
philpem@5 7897 return *this;
philpem@5 7898 }
philpem@5 7899
philpem@5 7900 CImgDisplay& move(const int posx, const int posy) {
philpem@5 7901 if (is_empty()) return *this;
philpem@5 7902 show();
philpem@5 7903 XLockDisplay(cimg::X11attr().display);
philpem@5 7904 XMoveWindow(cimg::X11attr().display,window,posx,posy);
philpem@5 7905 window_x = posx; window_y = posy;
philpem@5 7906 is_moved = false;
philpem@5 7907 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7908 return paint();
philpem@5 7909 }
philpem@5 7910
philpem@5 7911 CImgDisplay& show_mouse() {
philpem@5 7912 if (is_empty()) return *this;
philpem@5 7913 XLockDisplay(cimg::X11attr().display);
philpem@5 7914 XDefineCursor(cimg::X11attr().display,window,None);
philpem@5 7915 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7916 return *this;
philpem@5 7917 }
philpem@5 7918
philpem@5 7919 CImgDisplay& hide_mouse() {
philpem@5 7920 if (is_empty()) return *this;
philpem@5 7921 XLockDisplay(cimg::X11attr().display);
philpem@5 7922 const char pix_data[8] = { 0 };
philpem@5 7923 XColor col;
philpem@5 7924 col.red = col.green = col.blue = 0;
philpem@5 7925 Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8);
philpem@5 7926 Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0);
philpem@5 7927 XFreePixmap(cimg::X11attr().display,pix);
philpem@5 7928 XDefineCursor(cimg::X11attr().display,window,cur);
philpem@5 7929 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7930 return *this;
philpem@5 7931 }
philpem@5 7932
philpem@5 7933 CImgDisplay& set_mouse(const int posx, const int posy) {
philpem@5 7934 if (is_empty() || is_closed) return *this;
philpem@5 7935 XLockDisplay(cimg::X11attr().display);
philpem@5 7936 XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy);
philpem@5 7937 mouse_x = posx; mouse_y = posy;
philpem@5 7938 is_moved = false;
philpem@5 7939 XSync(cimg::X11attr().display, False);
philpem@5 7940 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7941 return *this;
philpem@5 7942 }
philpem@5 7943
philpem@5 7944 CImgDisplay& set_title(const char *format, ...) {
philpem@5 7945 if (is_empty()) return *this;
philpem@5 7946 char tmp[1024] = {0};
philpem@5 7947 va_list ap;
philpem@5 7948 va_start(ap, format);
philpem@5 7949 cimg_std::vsprintf(tmp,format,ap);
philpem@5 7950 va_end(ap);
philpem@5 7951 if (title) delete[] title;
philpem@5 7952 const int s = cimg::strlen(tmp)+1;
philpem@5 7953 title = new char[s];
philpem@5 7954 cimg_std::memcpy(title,tmp,s*sizeof(char));
philpem@5 7955 XLockDisplay(cimg::X11attr().display);
philpem@5 7956 XStoreName(cimg::X11attr().display,window,tmp);
philpem@5 7957 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7958 return *this;
philpem@5 7959 }
philpem@5 7960
philpem@5 7961 template<typename T>
philpem@5 7962 CImgDisplay& display(const CImg<T>& img) {
philpem@5 7963 if (img.is_empty())
philpem@5 7964 throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
philpem@5 7965 if (is_empty()) assign(img.width,img.height);
philpem@5 7966 return render(img).paint(false);
philpem@5 7967 }
philpem@5 7968
philpem@5 7969 CImgDisplay& paint(const bool wait_expose=true) {
philpem@5 7970 if (is_empty()) return *this;
philpem@5 7971 XLockDisplay(cimg::X11attr().display);
philpem@5 7972 _paint(wait_expose);
philpem@5 7973 XUnlockDisplay(cimg::X11attr().display);
philpem@5 7974 return *this;
philpem@5 7975 }
philpem@5 7976
philpem@5 7977 template<typename T>
philpem@5 7978 CImgDisplay& render(const CImg<T>& img, const bool flag8=false) {
philpem@5 7979 if (is_empty()) return *this;
philpem@5 7980 if (!img)
philpem@5 7981 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
philpem@5 7982 img.width,img.height,img.depth,img.dim,img.data);
philpem@5 7983 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 7984 if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1));
philpem@5 7985 if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true);
philpem@5 7986
philpem@5 7987 const T
philpem@5 7988 *data1 = img.data,
philpem@5 7989 *data2 = (img.dim>1)?img.ptr(0,0,0,1):data1,
philpem@5 7990 *data3 = (img.dim>2)?img.ptr(0,0,0,2):data1;
philpem@5 7991
philpem@5 7992 if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
philpem@5 7993 XLockDisplay(cimg::X11attr().display);
philpem@5 7994
philpem@5 7995 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
philpem@5 7996 min = max = 0;
philpem@5 7997 switch (cimg::X11attr().nb_bits) {
philpem@5 7998 case 8 : { // 256 color palette, no normalization
philpem@5 7999 _set_colormap(colormap,img.dim);
philpem@5 8000 unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
philpem@5 8001 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8002 switch (img.dim) {
philpem@5 8003 case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) (*ptrd++) = (unsigned char)*(data1++);
philpem@5 8004 break;
philpem@5 8005 case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8006 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++);
philpem@5 8007 (*ptrd++) = (R&0xf0) | (G>>4);
philpem@5 8008 } break;
philpem@5 8009 default : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8010 const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++);
philpem@5 8011 (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
philpem@5 8012 }
philpem@5 8013 }
philpem@5 8014 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
philpem@5 8015 } break;
philpem@5 8016 case 16 : { // 16 bits colors, no normalization
philpem@5 8017 unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
philpem@5 8018 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8019 const unsigned int M = 248;
philpem@5 8020 switch (img.dim) {
philpem@5 8021 case 1 :
philpem@5 8022 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8023 const unsigned char val = (unsigned char)*(data1++), G = val>>2;
philpem@5 8024 *(ptrd++) = (val&M) | (G>>3);
philpem@5 8025 *(ptrd++) = (G<<5) | (G>>1);
philpem@5 8026 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8027 const unsigned char val = (unsigned char)*(data1++), G = val>>2;
philpem@5 8028 *(ptrd++) = (G<<5) | (G>>1);
philpem@5 8029 *(ptrd++) = (val&M) | (G>>3);
philpem@5 8030 }
philpem@5 8031 break;
philpem@5 8032 case 2 :
philpem@5 8033 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8034 const unsigned char G = (unsigned char)*(data2++)>>2;
philpem@5 8035 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
philpem@5 8036 *(ptrd++) = (G<<5);
philpem@5 8037 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8038 const unsigned char G = (unsigned char)*(data2++)>>2;
philpem@5 8039 *(ptrd++) = (G<<5);
philpem@5 8040 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
philpem@5 8041 }
philpem@5 8042 break;
philpem@5 8043 default :
philpem@5 8044 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8045 const unsigned char G = (unsigned char)*(data2++)>>2;
philpem@5 8046 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
philpem@5 8047 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
philpem@5 8048 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8049 const unsigned char G = (unsigned char)*(data2++)>>2;
philpem@5 8050 *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3);
philpem@5 8051 *(ptrd++) = ((unsigned char)*(data1++)&M) | (G>>3);
philpem@5 8052 }
philpem@5 8053 }
philpem@5 8054 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
philpem@5 8055 } break;
philpem@5 8056 default : { // 24 bits colors, no normalization
philpem@5 8057 unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
philpem@5 8058 if (sizeof(int)==4) { // 32 bits int uses optimized version
philpem@5 8059 unsigned int *ptrd = ndata;
philpem@5 8060 switch (img.dim) {
philpem@5 8061 case 1 :
philpem@5 8062 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8063 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8064 const unsigned char val = (unsigned char)*(data1++);
philpem@5 8065 *(ptrd++) = (val<<16) | (val<<8) | val;
philpem@5 8066 }
philpem@5 8067 else
philpem@5 8068 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8069 const unsigned char val = (unsigned char)*(data1++)<<8;
philpem@5 8070 *(ptrd++) = (val<<16) | (val<<8) | val;
philpem@5 8071 }
philpem@5 8072 break;
philpem@5 8073 case 2 :
philpem@5 8074 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8075 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8076 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
philpem@5 8077 else
philpem@5 8078 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8079 *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
philpem@5 8080 break;
philpem@5 8081 default :
philpem@5 8082 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8083 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8084 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
philpem@5 8085 else
philpem@5 8086 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8087 *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8);
philpem@5 8088 }
philpem@5 8089 } else {
philpem@5 8090 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8091 switch (img.dim) {
philpem@5 8092 case 1 :
philpem@5 8093 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8094 *(ptrd++) = 0;
philpem@5 8095 *(ptrd++) = (unsigned char)*(data1++);
philpem@5 8096 *(ptrd++) = 0;
philpem@5 8097 *(ptrd++) = 0;
philpem@5 8098 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8099 *(ptrd++) = 0;
philpem@5 8100 *(ptrd++) = 0;
philpem@5 8101 *(ptrd++) = (unsigned char)*(data1++);
philpem@5 8102 *(ptrd++) = 0;
philpem@5 8103 }
philpem@5 8104 break;
philpem@5 8105 case 2 :
philpem@5 8106 if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
philpem@5 8107 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8108 *(ptrd++) = 0;
philpem@5 8109 *(ptrd++) = (unsigned char)*(data2++);
philpem@5 8110 *(ptrd++) = (unsigned char)*(data1++);
philpem@5 8111 *(ptrd++) = 0;
philpem@5 8112 }
philpem@5 8113 break;
philpem@5 8114 default :
philpem@5 8115 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8116 *(ptrd++) = 0;
philpem@5 8117 *(ptrd++) = (unsigned char)*(data1++);
philpem@5 8118 *(ptrd++) = (unsigned char)*(data2++);
philpem@5 8119 *(ptrd++) = (unsigned char)*(data3++);
philpem@5 8120 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8121 *(ptrd++) = (unsigned char)*(data3++);
philpem@5 8122 *(ptrd++) = (unsigned char)*(data2++);
philpem@5 8123 *(ptrd++) = (unsigned char)*(data1++);
philpem@5 8124 *(ptrd++) = 0;
philpem@5 8125 }
philpem@5 8126 }
philpem@5 8127 }
philpem@5 8128 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
philpem@5 8129 }
philpem@5 8130 };
philpem@5 8131 } else {
philpem@5 8132 if (normalization==3) {
philpem@5 8133 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
philpem@5 8134 else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
philpem@5 8135 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
philpem@5 8136 const float delta = max-min, mm = delta?delta:1.0f;
philpem@5 8137 switch (cimg::X11attr().nb_bits) {
philpem@5 8138 case 8 : { // 256 color palette, with normalization
philpem@5 8139 _set_colormap(colormap,img.dim);
philpem@5 8140 unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height];
philpem@5 8141 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8142 switch (img.dim) {
philpem@5 8143 case 1 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8144 const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8145 *(ptrd++) = R;
philpem@5 8146 } break;
philpem@5 8147 case 2 : for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8148 const unsigned char
philpem@5 8149 R = (unsigned char)(255*(*(data1++)-min)/mm),
philpem@5 8150 G = (unsigned char)(255*(*(data2++)-min)/mm);
philpem@5 8151 (*ptrd++) = (R&0xf0) | (G>>4);
philpem@5 8152 } break;
philpem@5 8153 default :
philpem@5 8154 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8155 const unsigned char
philpem@5 8156 R = (unsigned char)(255*(*(data1++)-min)/mm),
philpem@5 8157 G = (unsigned char)(255*(*(data2++)-min)/mm),
philpem@5 8158 B = (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 8159 *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6);
philpem@5 8160 }
philpem@5 8161 }
philpem@5 8162 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; }
philpem@5 8163 } break;
philpem@5 8164 case 16 : { // 16 bits colors, with normalization
philpem@5 8165 unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height];
philpem@5 8166 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8167 const unsigned int M = 248;
philpem@5 8168 switch (img.dim) {
philpem@5 8169 case 1 :
philpem@5 8170 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8171 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
philpem@5 8172 *(ptrd++) = (val&M) | (G>>3);
philpem@5 8173 *(ptrd++) = (G<<5) | (val>>3);
philpem@5 8174 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8175 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm), G = val>>2;
philpem@5 8176 *(ptrd++) = (G<<5) | (val>>3);
philpem@5 8177 *(ptrd++) = (val&M) | (G>>3);
philpem@5 8178 }
philpem@5 8179 break;
philpem@5 8180 case 2 :
philpem@5 8181 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8182 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
philpem@5 8183 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
philpem@5 8184 *(ptrd++) = (G<<5);
philpem@5 8185 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8186 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
philpem@5 8187 *(ptrd++) = (G<<5);
philpem@5 8188 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
philpem@5 8189 }
philpem@5 8190 break;
philpem@5 8191 default :
philpem@5 8192 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8193 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
philpem@5 8194 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
philpem@5 8195 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
philpem@5 8196 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8197 const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>2;
philpem@5 8198 *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3);
philpem@5 8199 *(ptrd++) = ((unsigned char)(255*(*(data1++)-min)/mm)&M) | (G>>3);
philpem@5 8200 }
philpem@5 8201 }
philpem@5 8202 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; }
philpem@5 8203 } break;
philpem@5 8204 default : { // 24 bits colors, with normalization
philpem@5 8205 unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height];
philpem@5 8206 if (sizeof(int)==4) { // 32 bits int uses optimized version
philpem@5 8207 unsigned int *ptrd = ndata;
philpem@5 8208 switch (img.dim) {
philpem@5 8209 case 1 :
philpem@5 8210 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8211 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8212 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8213 *(ptrd++) = (val<<16) | (val<<8) | val;
philpem@5 8214 }
philpem@5 8215 else
philpem@5 8216 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8217 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8218 *(ptrd++) = (val<<24) | (val<<16) | (val<<8);
philpem@5 8219 }
philpem@5 8220 break;
philpem@5 8221 case 2 :
philpem@5 8222 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8223 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8224 *(ptrd++) =
philpem@5 8225 ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
philpem@5 8226 ((unsigned char)(255*(*(data2++)-min)/mm)<<8);
philpem@5 8227 else
philpem@5 8228 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8229 *(ptrd++) =
philpem@5 8230 ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
philpem@5 8231 ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
philpem@5 8232 break;
philpem@5 8233 default :
philpem@5 8234 if (cimg::X11attr().byte_order==cimg::endianness())
philpem@5 8235 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8236 *(ptrd++) =
philpem@5 8237 ((unsigned char)(255*(*(data1++)-min)/mm)<<16) |
philpem@5 8238 ((unsigned char)(255*(*(data2++)-min)/mm)<<8) |
philpem@5 8239 (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 8240 else
philpem@5 8241 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8242 *(ptrd++) =
philpem@5 8243 ((unsigned char)(255*(*(data3++)-min)/mm)<<24) |
philpem@5 8244 ((unsigned char)(255*(*(data2++)-min)/mm)<<16) |
philpem@5 8245 ((unsigned char)(255*(*(data1++)-min)/mm)<<8);
philpem@5 8246 }
philpem@5 8247 } else {
philpem@5 8248 unsigned char *ptrd = (unsigned char*)ndata;
philpem@5 8249 switch (img.dim) {
philpem@5 8250 case 1 :
philpem@5 8251 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8252 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8253 (*ptrd++) = 0;
philpem@5 8254 (*ptrd++) = val;
philpem@5 8255 (*ptrd++) = val;
philpem@5 8256 (*ptrd++) = val;
philpem@5 8257 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8258 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8259 (*ptrd++) = val;
philpem@5 8260 (*ptrd++) = val;
philpem@5 8261 (*ptrd++) = val;
philpem@5 8262 (*ptrd++) = 0;
philpem@5 8263 }
philpem@5 8264 break;
philpem@5 8265 case 2 :
philpem@5 8266 if (cimg::X11attr().byte_order) cimg::swap(data1,data2);
philpem@5 8267 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8268 (*ptrd++) = 0;
philpem@5 8269 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
philpem@5 8270 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8271 (*ptrd++) = 0;
philpem@5 8272 }
philpem@5 8273 break;
philpem@5 8274 default :
philpem@5 8275 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8276 (*ptrd++) = 0;
philpem@5 8277 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8278 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
philpem@5 8279 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 8280 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8281 (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 8282 (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm);
philpem@5 8283 (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8284 (*ptrd++) = 0;
philpem@5 8285 }
philpem@5 8286 }
philpem@5 8287 }
philpem@5 8288 if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; }
philpem@5 8289 }
philpem@5 8290 }
philpem@5 8291 }
philpem@5 8292 XUnlockDisplay(cimg::X11attr().display);
philpem@5 8293 return *this;
philpem@5 8294 }
philpem@5 8295
philpem@5 8296 template<typename T>
philpem@5 8297 const CImgDisplay& snapshot(CImg<T>& img) const {
philpem@5 8298 if (is_empty()) img.assign();
philpem@5 8299 else {
philpem@5 8300 img.assign(width,height,1,3);
philpem@5 8301 T
philpem@5 8302 *data1 = img.ptr(0,0,0,0),
philpem@5 8303 *data2 = img.ptr(0,0,0,1),
philpem@5 8304 *data3 = img.ptr(0,0,0,2);
philpem@5 8305 if (cimg::X11attr().blue_first) cimg::swap(data1,data3);
philpem@5 8306 switch (cimg::X11attr().nb_bits) {
philpem@5 8307 case 8 : {
philpem@5 8308 unsigned char *ptrs = (unsigned char*)data;
philpem@5 8309 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8310 const unsigned char val = *(ptrs++);
philpem@5 8311 *(data1++) = val&0xe0;
philpem@5 8312 *(data2++) = (val&0x1c)<<3;
philpem@5 8313 *(data3++) = val<<6;
philpem@5 8314 }
philpem@5 8315 } break;
philpem@5 8316 case 16 : {
philpem@5 8317 unsigned char *ptrs = (unsigned char*)data;
philpem@5 8318 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8319 const unsigned char val0 = *(ptrs++), val1 = *(ptrs++);
philpem@5 8320 *(data1++) = val0&0xf8;
philpem@5 8321 *(data2++) = (val0<<5) | ((val1&0xe0)>>5);
philpem@5 8322 *(data3++) = val1<<3;
philpem@5 8323 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8324 const unsigned short val0 = *(ptrs++), val1 = *(ptrs++);
philpem@5 8325 *(data1++) = val1&0xf8;
philpem@5 8326 *(data2++) = (val1<<5) | ((val0&0xe0)>>5);
philpem@5 8327 *(data3++) = val0<<3;
philpem@5 8328 }
philpem@5 8329 } break;
philpem@5 8330 default : {
philpem@5 8331 unsigned char *ptrs = (unsigned char*)data;
philpem@5 8332 if (cimg::X11attr().byte_order) for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8333 ++ptrs;
philpem@5 8334 *(data1++) = *(ptrs++);
philpem@5 8335 *(data2++) = *(ptrs++);
philpem@5 8336 *(data3++) = *(ptrs++);
philpem@5 8337 } else for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8338 *(data3++) = *(ptrs++);
philpem@5 8339 *(data2++) = *(ptrs++);
philpem@5 8340 *(data1++) = *(ptrs++);
philpem@5 8341 ++ptrs;
philpem@5 8342 }
philpem@5 8343 }
philpem@5 8344 }
philpem@5 8345 }
philpem@5 8346 return *this;
philpem@5 8347 }
philpem@5 8348
philpem@5 8349 // Windows-based display
philpem@5 8350 //-----------------------
philpem@5 8351 #elif cimg_display==2
philpem@5 8352 CLIENTCREATESTRUCT ccs;
philpem@5 8353 BITMAPINFO bmi;
philpem@5 8354 unsigned int *data;
philpem@5 8355 DEVMODE curr_mode;
philpem@5 8356 HWND window;
philpem@5 8357 HWND background_window;
philpem@5 8358 HDC hdc;
philpem@5 8359 HANDLE thread;
philpem@5 8360 HANDLE created;
philpem@5 8361 HANDLE mutex;
philpem@5 8362 bool mouse_tracking;
philpem@5 8363 bool visible_cursor;
philpem@5 8364
philpem@5 8365 static int screen_dimx() {
philpem@5 8366 DEVMODE mode;
philpem@5 8367 mode.dmSize = sizeof(DEVMODE);
philpem@5 8368 mode.dmDriverExtra = 0;
philpem@5 8369 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
philpem@5 8370 return mode.dmPelsWidth;
philpem@5 8371 }
philpem@5 8372
philpem@5 8373 static int screen_dimy() {
philpem@5 8374 DEVMODE mode;
philpem@5 8375 mode.dmSize = sizeof(DEVMODE);
philpem@5 8376 mode.dmDriverExtra = 0;
philpem@5 8377 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode);
philpem@5 8378 return mode.dmPelsHeight;
philpem@5 8379 }
philpem@5 8380
philpem@5 8381 static void wait_all() {
philpem@5 8382 WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE);
philpem@5 8383 }
philpem@5 8384
philpem@5 8385 static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) {
philpem@5 8386 #ifdef _WIN64
philpem@5 8387 CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA);
philpem@5 8388 #else
philpem@5 8389 CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA);
philpem@5 8390 #endif
philpem@5 8391 MSG st_msg;
philpem@5 8392
philpem@5 8393 switch (msg) {
philpem@5 8394 case WM_CLOSE :
philpem@5 8395 disp->mouse_x = disp->mouse_y = -1;
philpem@5 8396 disp->window_x = disp->window_y = 0;
philpem@5 8397 if (disp->button) {
philpem@5 8398 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8399 disp->button = 0;
philpem@5 8400 }
philpem@5 8401 if (disp->key) {
philpem@5 8402 cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
philpem@5 8403 disp->key = 0;
philpem@5 8404 }
philpem@5 8405 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
philpem@5 8406 disp->is_closed = true;
philpem@5 8407 ReleaseMutex(disp->mutex);
philpem@5 8408 ShowWindow(disp->window,SW_HIDE);
philpem@5 8409 disp->is_event = true;
philpem@5 8410 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8411 return 0;
philpem@5 8412 case WM_SIZE : {
philpem@5 8413 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
philpem@5 8414 WaitForSingleObject(disp->mutex,INFINITE);
philpem@5 8415 const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam);
philpem@5 8416 if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
philpem@5 8417 disp->window_width = nw;
philpem@5 8418 disp->window_height = nh;
philpem@5 8419 disp->mouse_x = disp->mouse_y = -1;
philpem@5 8420 disp->is_resized = disp->is_event = true;
philpem@5 8421 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8422 }
philpem@5 8423 ReleaseMutex(disp->mutex);
philpem@5 8424 } break;
philpem@5 8425 case WM_MOVE : {
philpem@5 8426 while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {}
philpem@5 8427 WaitForSingleObject(disp->mutex,INFINITE);
philpem@5 8428 const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam));
philpem@5 8429 if (nx!=disp->window_x || ny!=disp->window_y) {
philpem@5 8430 disp->window_x = nx;
philpem@5 8431 disp->window_y = ny;
philpem@5 8432 disp->is_moved = disp->is_event = true;
philpem@5 8433 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8434 }
philpem@5 8435 ReleaseMutex(disp->mutex);
philpem@5 8436 } break;
philpem@5 8437 case WM_PAINT :
philpem@5 8438 disp->paint();
philpem@5 8439 break;
philpem@5 8440 case WM_KEYDOWN :
philpem@5 8441 disp->update_iskey((unsigned int)wParam,true);
philpem@5 8442 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
philpem@5 8443 disp->key = (unsigned int)wParam;
philpem@5 8444 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
philpem@5 8445 disp->is_event = true;
philpem@5 8446 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8447 break;
philpem@5 8448 case WM_MOUSEMOVE : {
philpem@5 8449 while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {}
philpem@5 8450 disp->mouse_x = LOWORD(lParam);
philpem@5 8451 disp->mouse_y = HIWORD(lParam);
philpem@5 8452 #if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT)
philpem@5 8453 if (!disp->mouse_tracking) {
philpem@5 8454 TRACKMOUSEEVENT tme;
philpem@5 8455 tme.cbSize = sizeof(TRACKMOUSEEVENT);
philpem@5 8456 tme.dwFlags = TME_LEAVE;
philpem@5 8457 tme.hwndTrack = disp->window;
philpem@5 8458 if (TrackMouseEvent(&tme)) disp->mouse_tracking = true;
philpem@5 8459 }
philpem@5 8460 #endif
philpem@5 8461 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
philpem@5 8462 disp->mouse_x = disp->mouse_y = -1;
philpem@5 8463 disp->is_event = true;
philpem@5 8464 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8465 } break;
philpem@5 8466 case WM_MOUSELEAVE : {
philpem@5 8467 disp->mouse_x = disp->mouse_y = -1;
philpem@5 8468 disp->mouse_tracking = false;
philpem@5 8469 } break;
philpem@5 8470 case WM_LBUTTONDOWN :
philpem@5 8471 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8472 disp->button|=1U;
philpem@5 8473 disp->is_event = true;
philpem@5 8474 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8475 break;
philpem@5 8476 case WM_RBUTTONDOWN :
philpem@5 8477 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8478 disp->button|=2U;
philpem@5 8479 disp->is_event = true;
philpem@5 8480 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8481 break;
philpem@5 8482 case WM_MBUTTONDOWN :
philpem@5 8483 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8484 disp->button|=4U;
philpem@5 8485 disp->is_event = true;
philpem@5 8486 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8487 break;
philpem@5 8488 case 0x020A : // WM_MOUSEWHEEL:
philpem@5 8489 disp->wheel+=(int)((short)HIWORD(wParam))/120;
philpem@5 8490 disp->is_event = true;
philpem@5 8491 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8492 case WM_KEYUP :
philpem@5 8493 disp->update_iskey((unsigned int)wParam,false);
philpem@5 8494 if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
philpem@5 8495 if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
philpem@5 8496 disp->released_key = (unsigned int)wParam;
philpem@5 8497 disp->is_event = true;
philpem@5 8498 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8499 break;
philpem@5 8500 case WM_LBUTTONUP :
philpem@5 8501 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8502 disp->button&=~1U;
philpem@5 8503 disp->is_event = true;
philpem@5 8504 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8505 break;
philpem@5 8506 case WM_RBUTTONUP :
philpem@5 8507 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8508 disp->button&=~2U;
philpem@5 8509 disp->is_event = true;
philpem@5 8510 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8511 break;
philpem@5 8512 case WM_MBUTTONUP :
philpem@5 8513 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 8514 disp->button&=~4U;
philpem@5 8515 disp->is_event = true;
philpem@5 8516 SetEvent(cimg::Win32attr().wait_event);
philpem@5 8517 break;
philpem@5 8518 case WM_SETCURSOR :
philpem@5 8519 if (disp->visible_cursor) ShowCursor(TRUE);
philpem@5 8520 else ShowCursor(FALSE);
philpem@5 8521 break;
philpem@5 8522 }
philpem@5 8523 return DefWindowProc(window,msg,wParam,lParam);
philpem@5 8524 }
philpem@5 8525
philpem@5 8526 static DWORD WINAPI _events_thread(void* arg) {
philpem@5 8527 CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]);
philpem@5 8528 const char *title = (const char*)(((void**)arg)[1]);
philpem@5 8529 MSG msg;
philpem@5 8530 delete[] (void**)arg;
philpem@5 8531 disp->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
philpem@5 8532 disp->bmi.bmiHeader.biWidth = disp->width;
philpem@5 8533 disp->bmi.bmiHeader.biHeight = -(int)disp->height;
philpem@5 8534 disp->bmi.bmiHeader.biPlanes = 1;
philpem@5 8535 disp->bmi.bmiHeader.biBitCount = 32;
philpem@5 8536 disp->bmi.bmiHeader.biCompression = BI_RGB;
philpem@5 8537 disp->bmi.bmiHeader.biSizeImage = 0;
philpem@5 8538 disp->bmi.bmiHeader.biXPelsPerMeter = 1;
philpem@5 8539 disp->bmi.bmiHeader.biYPelsPerMeter = 1;
philpem@5 8540 disp->bmi.bmiHeader.biClrUsed = 0;
philpem@5 8541 disp->bmi.bmiHeader.biClrImportant = 0;
philpem@5 8542 disp->data = new unsigned int[disp->width*disp->height];
philpem@5 8543 if (!disp->is_fullscreen) { // Normal window
philpem@5 8544 RECT rect;
philpem@5 8545 rect.left = rect.top = 0; rect.right = disp->width-1; rect.bottom = disp->height-1;
philpem@5 8546 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
philpem@5 8547 const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1;
philpem@5 8548 disp->window = CreateWindowA("MDICLIENT",title?title:" ",
philpem@5 8549 WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT,
philpem@5 8550 disp->width + 2*border1, disp->height + border1 + border2,
philpem@5 8551 0,0,0,&(disp->ccs));
philpem@5 8552 if (!disp->is_closed) {
philpem@5 8553 GetWindowRect(disp->window,&rect);
philpem@5 8554 disp->window_x = rect.left + border1;
philpem@5 8555 disp->window_y = rect.top + border2;
philpem@5 8556 } else disp->window_x = disp->window_y = 0;
philpem@5 8557 } else { // Fullscreen window
philpem@5 8558 const unsigned int sx = screen_dimx(), sy = screen_dimy();
philpem@5 8559 disp->window = CreateWindowA("MDICLIENT",title?title:" ",
philpem@5 8560 WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2,
philpem@5 8561 disp->width,disp->height,0,0,0,&(disp->ccs));
philpem@5 8562 disp->window_x = disp->window_y = 0;
philpem@5 8563 }
philpem@5 8564 SetForegroundWindow(disp->window);
philpem@5 8565 disp->hdc = GetDC(disp->window);
philpem@5 8566 disp->window_width = disp->width;
philpem@5 8567 disp->window_height = disp->height;
philpem@5 8568 disp->flush();
philpem@5 8569 #ifdef _WIN64
philpem@5 8570 SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp);
philpem@5 8571 SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events);
philpem@5 8572 #else
philpem@5 8573 SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp);
philpem@5 8574 SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events);
philpem@5 8575 #endif
philpem@5 8576 SetEvent(disp->created);
philpem@5 8577 while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);
philpem@5 8578 return 0;
philpem@5 8579 }
philpem@5 8580
philpem@5 8581 CImgDisplay& _update_window_pos() {
philpem@5 8582 if (!is_closed) {
philpem@5 8583 RECT rect;
philpem@5 8584 rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1;
philpem@5 8585 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
philpem@5 8586 const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
philpem@5 8587 GetWindowRect(window,&rect);
philpem@5 8588 window_x = rect.left + border1;
philpem@5 8589 window_y = rect.top + border2;
philpem@5 8590 } else window_x = window_y = -1;
philpem@5 8591 return *this;
philpem@5 8592 }
philpem@5 8593
philpem@5 8594 void _init_fullscreen() {
philpem@5 8595 background_window = 0;
philpem@5 8596 if (is_fullscreen && !is_closed) {
philpem@5 8597 DEVMODE mode;
philpem@5 8598 unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U;
philpem@5 8599 for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) {
philpem@5 8600 const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight;
philpem@5 8601 if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) {
philpem@5 8602 bestbpp = mode.dmBitsPerPel;
philpem@5 8603 ibest = imode;
philpem@5 8604 bw = nw; bh = nh;
philpem@5 8605 }
philpem@5 8606 }
philpem@5 8607 if (bestbpp) {
philpem@5 8608 curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0;
philpem@5 8609 EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode);
philpem@5 8610 EnumDisplaySettings(0,ibest,&mode);
philpem@5 8611 ChangeDisplaySettings(&mode,0);
philpem@5 8612 } else curr_mode.dmSize = 0;
philpem@5 8613
philpem@5 8614 const unsigned int sx = screen_dimx(), sy = screen_dimy();
philpem@5 8615 if (sx!=width || sy!=height) {
philpem@5 8616 CLIENTCREATESTRUCT background_ccs;
philpem@5 8617 background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs);
philpem@5 8618 SetForegroundWindow(background_window);
philpem@5 8619 }
philpem@5 8620 } else curr_mode.dmSize = 0;
philpem@5 8621 }
philpem@5 8622
philpem@5 8623 void _desinit_fullscreen() {
philpem@5 8624 if (is_fullscreen) {
philpem@5 8625 if (background_window) DestroyWindow(background_window);
philpem@5 8626 background_window = 0;
philpem@5 8627 if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0);
philpem@5 8628 is_fullscreen = false;
philpem@5 8629 }
philpem@5 8630 }
philpem@5 8631
philpem@5 8632 CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
philpem@5 8633 const unsigned int normalization_type=3,
philpem@5 8634 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 8635
philpem@5 8636 // Allocate space for window title
philpem@5 8637 const int s = cimg::strlen(ptitle)+1;
philpem@5 8638 char *tmp_title = s?new char[s]:0;
philpem@5 8639 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
philpem@5 8640
philpem@5 8641 // Destroy previous window if existing
philpem@5 8642 if (!is_empty()) assign();
philpem@5 8643
philpem@5 8644 // Set display variables
philpem@5 8645 width = cimg::min(dimw,(unsigned int)screen_dimx());
philpem@5 8646 height = cimg::min(dimh,(unsigned int)screen_dimy());
philpem@5 8647 normalization = normalization_type<4?normalization_type:3;
philpem@5 8648 is_fullscreen = fullscreen_flag;
philpem@5 8649 window_x = window_y = 0;
philpem@5 8650 is_closed = closed_flag;
philpem@5 8651 visible_cursor = true;
philpem@5 8652 mouse_tracking = false;
philpem@5 8653 title = tmp_title;
philpem@5 8654 flush();
philpem@5 8655 if (is_fullscreen) _init_fullscreen();
philpem@5 8656
philpem@5 8657 // Create event thread
philpem@5 8658 void *arg = (void*)(new void*[2]);
philpem@5 8659 ((void**)arg)[0]=(void*)this;
philpem@5 8660 ((void**)arg)[1]=(void*)title;
philpem@5 8661 unsigned long ThreadID = 0;
philpem@5 8662 mutex = CreateMutex(0,FALSE,0);
philpem@5 8663 created = CreateEvent(0,FALSE,FALSE,0);
philpem@5 8664 thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID);
philpem@5 8665 WaitForSingleObject(created,INFINITE);
philpem@5 8666 return *this;
philpem@5 8667 }
philpem@5 8668
philpem@5 8669 CImgDisplay& assign() {
philpem@5 8670 if (is_empty()) return *this;
philpem@5 8671 DestroyWindow(window);
philpem@5 8672 TerminateThread(thread,0);
philpem@5 8673 if (data) delete[] data;
philpem@5 8674 if (title) delete[] title;
philpem@5 8675 if (is_fullscreen) _desinit_fullscreen();
philpem@5 8676 width = height = normalization = window_width = window_height = 0;
philpem@5 8677 window_x = window_y = 0;
philpem@5 8678 is_fullscreen = false;
philpem@5 8679 is_closed = true;
philpem@5 8680 min = max = 0;
philpem@5 8681 title = 0;
philpem@5 8682 flush();
philpem@5 8683 return *this;
philpem@5 8684 }
philpem@5 8685
philpem@5 8686 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
philpem@5 8687 const unsigned int normalization_type=3,
philpem@5 8688 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 8689 if (!dimw || !dimh) return assign();
philpem@5 8690 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 8691 min = max = 0;
philpem@5 8692 cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
philpem@5 8693 return paint();
philpem@5 8694 }
philpem@5 8695
philpem@5 8696 template<typename T>
philpem@5 8697 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
philpem@5 8698 const unsigned int normalization_type=3,
philpem@5 8699 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 8700 if (!img) return assign();
philpem@5 8701 CImg<T> tmp;
philpem@5 8702 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 8703 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 8704 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 8705 return display(nimg);
philpem@5 8706 }
philpem@5 8707
philpem@5 8708 template<typename T>
philpem@5 8709 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
philpem@5 8710 const unsigned int normalization_type=3,
philpem@5 8711 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 8712 if (!list) return assign();
philpem@5 8713 CImg<T> tmp;
philpem@5 8714 const CImg<T> img = list.get_append('x','p'),
philpem@5 8715 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 8716 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 8717 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 8718 return display(nimg);
philpem@5 8719 }
philpem@5 8720
philpem@5 8721 CImgDisplay& assign(const CImgDisplay& win) {
philpem@5 8722 if (!win) return assign();
philpem@5 8723 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
philpem@5 8724 cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
philpem@5 8725 return paint();
philpem@5 8726 }
philpem@5 8727
philpem@5 8728 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
philpem@5 8729 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
philpem@5 8730 if (is_empty()) return assign(nwidth,nheight);
philpem@5 8731 const unsigned int
philpem@5 8732 tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100),
philpem@5 8733 tmpdimy=(nheight>0)?nheight:(-nheight*height/100),
philpem@5 8734 dimx = tmpdimx?tmpdimx:1,
philpem@5 8735 dimy = tmpdimy?tmpdimy:1;
philpem@5 8736 if (window_width!=dimx || window_height!=dimy) {
philpem@5 8737 RECT rect; rect.left = rect.top = 0; rect.right = dimx-1; rect.bottom = dimy-1;
philpem@5 8738 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
philpem@5 8739 const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1;
philpem@5 8740 SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
philpem@5 8741 }
philpem@5 8742 if (width!=dimx || height!=dimy) {
philpem@5 8743 unsigned int *ndata = new unsigned int[dimx*dimy];
philpem@5 8744 if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
philpem@5 8745 else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
philpem@5 8746 delete[] data;
philpem@5 8747 data = ndata;
philpem@5 8748 bmi.bmiHeader.biWidth = dimx;
philpem@5 8749 bmi.bmiHeader.biHeight = -(int)dimy;
philpem@5 8750 width = dimx;
philpem@5 8751 height = dimy;
philpem@5 8752 }
philpem@5 8753 window_width = dimx; window_height = dimy;
philpem@5 8754 is_resized = false;
philpem@5 8755 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
philpem@5 8756 if (redraw) return paint();
philpem@5 8757 return *this;
philpem@5 8758 }
philpem@5 8759
philpem@5 8760 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
philpem@5 8761 if (is_empty()) return *this;
philpem@5 8762 if (redraw) {
philpem@5 8763 const unsigned int bufsize = width*height*4;
philpem@5 8764 void *odata = cimg_std::malloc(bufsize);
philpem@5 8765 cimg_std::memcpy(odata,data,bufsize);
philpem@5 8766 assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 8767 cimg_std::memcpy(data,odata,bufsize);
philpem@5 8768 cimg_std::free(odata);
philpem@5 8769 return paint();
philpem@5 8770 }
philpem@5 8771 return assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 8772 }
philpem@5 8773
philpem@5 8774 CImgDisplay& show() {
philpem@5 8775 if (is_empty()) return *this;
philpem@5 8776 if (is_closed) {
philpem@5 8777 is_closed = false;
philpem@5 8778 if (is_fullscreen) _init_fullscreen();
philpem@5 8779 ShowWindow(window,SW_SHOW);
philpem@5 8780 _update_window_pos();
philpem@5 8781 }
philpem@5 8782 return paint();
philpem@5 8783 }
philpem@5 8784
philpem@5 8785 CImgDisplay& close() {
philpem@5 8786 if (is_empty()) return *this;
philpem@5 8787 if (!is_closed && !is_fullscreen) {
philpem@5 8788 if (is_fullscreen) _desinit_fullscreen();
philpem@5 8789 ShowWindow(window,SW_HIDE);
philpem@5 8790 is_closed = true;
philpem@5 8791 window_x = window_y = 0;
philpem@5 8792 }
philpem@5 8793 return *this;
philpem@5 8794 }
philpem@5 8795
philpem@5 8796 CImgDisplay& move(const int posx, const int posy) {
philpem@5 8797 if (is_empty()) return *this;
philpem@5 8798 if (!is_fullscreen) {
philpem@5 8799 RECT rect; rect.left = rect.top = 0; rect.right=window_width-1; rect.bottom=window_height-1;
philpem@5 8800 AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false);
philpem@5 8801 const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1;
philpem@5 8802 SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER);
philpem@5 8803 } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER);
philpem@5 8804 window_x = posx;
philpem@5 8805 window_y = posy;
philpem@5 8806 is_moved = false;
philpem@5 8807 return show();
philpem@5 8808 }
philpem@5 8809
philpem@5 8810 CImgDisplay& show_mouse() {
philpem@5 8811 if (is_empty()) return *this;
philpem@5 8812 visible_cursor = true;
philpem@5 8813 ShowCursor(TRUE);
philpem@5 8814 SendMessage(window,WM_SETCURSOR,0,0);
philpem@5 8815 return *this;
philpem@5 8816 }
philpem@5 8817
philpem@5 8818 CImgDisplay& hide_mouse() {
philpem@5 8819 if (is_empty()) return *this;
philpem@5 8820 visible_cursor = false;
philpem@5 8821 ShowCursor(FALSE);
philpem@5 8822 SendMessage(window,WM_SETCURSOR,0,0);
philpem@5 8823 return *this;
philpem@5 8824 }
philpem@5 8825
philpem@5 8826 CImgDisplay& set_mouse(const int posx, const int posy) {
philpem@5 8827 if (!is_closed && posx>=0 && posy>=0) {
philpem@5 8828 _update_window_pos();
philpem@5 8829 const int res = (int)SetCursorPos(window_x+posx,window_y+posy);
philpem@5 8830 if (res) { mouse_x = posx; mouse_y = posy; }
philpem@5 8831 }
philpem@5 8832 return *this;
philpem@5 8833 }
philpem@5 8834
philpem@5 8835 CImgDisplay& set_title(const char *format, ...) {
philpem@5 8836 if (is_empty()) return *this;
philpem@5 8837 char tmp[1024] = {0};
philpem@5 8838 va_list ap;
philpem@5 8839 va_start(ap, format);
philpem@5 8840 cimg_std::vsprintf(tmp,format,ap);
philpem@5 8841 va_end(ap);
philpem@5 8842 if (title) delete[] title;
philpem@5 8843 const int s = cimg::strlen(tmp)+1;
philpem@5 8844 title = new char[s];
philpem@5 8845 cimg_std::memcpy(title,tmp,s*sizeof(char));
philpem@5 8846 SetWindowTextA(window, tmp);
philpem@5 8847 return *this;
philpem@5 8848 }
philpem@5 8849
philpem@5 8850 template<typename T>
philpem@5 8851 CImgDisplay& display(const CImg<T>& img) {
philpem@5 8852 if (img.is_empty())
philpem@5 8853 throw CImgArgumentException("CImgDisplay::display() : Cannot display empty image.");
philpem@5 8854 if (is_empty()) assign(img.width,img.height);
philpem@5 8855 return render(img).paint();
philpem@5 8856 }
philpem@5 8857
philpem@5 8858 CImgDisplay& paint() {
philpem@5 8859 if (!is_closed) {
philpem@5 8860 WaitForSingleObject(mutex,INFINITE);
philpem@5 8861 SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS);
philpem@5 8862 ReleaseMutex(mutex);
philpem@5 8863 }
philpem@5 8864 return *this;
philpem@5 8865 }
philpem@5 8866
philpem@5 8867 template<typename T>
philpem@5 8868 CImgDisplay& render(const CImg<T>& img) {
philpem@5 8869 if (is_empty()) return *this;
philpem@5 8870 if (!img)
philpem@5 8871 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
philpem@5 8872 img.width,img.height,img.depth,img.dim,img.data);
philpem@5 8873 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 8874
philpem@5 8875 const T
philpem@5 8876 *data1 = img.data,
philpem@5 8877 *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
philpem@5 8878 *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
philpem@5 8879
philpem@5 8880 WaitForSingleObject(mutex,INFINITE);
philpem@5 8881 unsigned int
philpem@5 8882 *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
philpem@5 8883 *ptrd = ndata;
philpem@5 8884
philpem@5 8885 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
philpem@5 8886 min = max = 0;
philpem@5 8887 switch (img.dim) {
philpem@5 8888 case 1 : {
philpem@5 8889 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8890 const unsigned char val = (unsigned char)*(data1++);
philpem@5 8891 *(ptrd++) = (val<<16) | (val<<8) | val;
philpem@5 8892 }} break;
philpem@5 8893 case 2 : {
philpem@5 8894 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8895 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8);
philpem@5 8896 } break;
philpem@5 8897 default : {
philpem@5 8898 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 8899 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
philpem@5 8900 }
philpem@5 8901 }
philpem@5 8902 } else {
philpem@5 8903 if (normalization==3) {
philpem@5 8904 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
philpem@5 8905 else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::max(); }
philpem@5 8906 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
philpem@5 8907 const float delta = max-min, mm = delta?delta:1.0f;
philpem@5 8908 switch (img.dim) {
philpem@5 8909 case 1 : {
philpem@5 8910 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8911 const unsigned char val = (unsigned char)(255*(*(data1++)-min)/mm);
philpem@5 8912 *(ptrd++) = (val<<16) | (val<<8) | val;
philpem@5 8913 }} break;
philpem@5 8914 case 2 : {
philpem@5 8915 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8916 const unsigned char
philpem@5 8917 R = (unsigned char)(255*(*(data1++)-min)/mm),
philpem@5 8918 G = (unsigned char)(255*(*(data2++)-min)/mm);
philpem@5 8919 *(ptrd++) = (R<<16) | (G<<8);
philpem@5 8920 }} break;
philpem@5 8921 default : {
philpem@5 8922 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8923 const unsigned char
philpem@5 8924 R = (unsigned char)(255*(*(data1++)-min)/mm),
philpem@5 8925 G = (unsigned char)(255*(*(data2++)-min)/mm),
philpem@5 8926 B = (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 8927 *(ptrd++) = (R<<16) | (G<<8) | B;
philpem@5 8928 }}
philpem@5 8929 }
philpem@5 8930 }
philpem@5 8931 if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; }
philpem@5 8932 ReleaseMutex(mutex);
philpem@5 8933 return *this;
philpem@5 8934 }
philpem@5 8935
philpem@5 8936 template<typename T>
philpem@5 8937 const CImgDisplay& snapshot(CImg<T>& img) const {
philpem@5 8938 if (is_empty()) img.assign();
philpem@5 8939 else {
philpem@5 8940 img.assign(width,height,1,3);
philpem@5 8941 T
philpem@5 8942 *data1 = img.ptr(0,0,0,0),
philpem@5 8943 *data2 = img.ptr(0,0,0,1),
philpem@5 8944 *data3 = img.ptr(0,0,0,2);
philpem@5 8945 unsigned int *ptrs = data;
philpem@5 8946 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 8947 const unsigned int val = *(ptrs++);
philpem@5 8948 *(data1++) = (unsigned char)(val>>16);
philpem@5 8949 *(data2++) = (unsigned char)((val>>8)&0xFF);
philpem@5 8950 *(data3++) = (unsigned char)(val&0xFF);
philpem@5 8951 }
philpem@5 8952 }
philpem@5 8953 return *this;
philpem@5 8954 }
philpem@5 8955
philpem@5 8956 // MacOSX - Carbon-based display
philpem@5 8957 //-------------------------------
philpem@5 8958 // (Code by Adrien Reboisson && Romain Blei, supervised by Jean-Marie Favreau)
philpem@5 8959 //
philpem@5 8960 #elif cimg_display==3
philpem@5 8961 unsigned int *data; // The bits of the picture
philpem@5 8962 WindowRef carbonWindow; // The opaque carbon window struct associated with the display
philpem@5 8963 MPCriticalRegionID paintCriticalRegion; // Critical section used when drawing
philpem@5 8964 CGColorSpaceRef csr; // Needed for painting
philpem@5 8965 CGDataProviderRef dataProvider; // Needed for painting
philpem@5 8966 CGImageRef imageRef; // The image
philpem@5 8967 UInt32 lastKeyModifiers; // Buffer storing modifiers state
philpem@5 8968
philpem@5 8969 // Define the kind of the queries which can be serialized using the event thread.
philpem@5 8970 typedef enum {
philpem@5 8971 COM_CREATEWINDOW = 0, // Create window query
philpem@5 8972 COM_RELEASEWINDOW, // Release window query
philpem@5 8973 COM_SHOWWINDOW, // Show window query
philpem@5 8974 COM_HIDEWINDOW, // Hide window query
philpem@5 8975 COM_SHOWMOUSE, // Show mouse query
philpem@5 8976 COM_HIDEMOUSE, // Hide mouse query
philpem@5 8977 COM_RESIZEWINDOW, // Resize window query
philpem@5 8978 COM_MOVEWINDOW, // Move window query
philpem@5 8979 COM_SETTITLE, // Set window title query
philpem@5 8980 COM_SETMOUSEPOS // Set cursor position query
philpem@5 8981 } CImgCarbonQueryKind;
philpem@5 8982
philpem@5 8983 // The query destructor send to the event thread.
philpem@5 8984 struct CbSerializedQuery {
philpem@5 8985 CImgDisplay* sender; // Query's sender
philpem@5 8986 CImgCarbonQueryKind kind; // The kind of the query sent to the background thread
philpem@5 8987 short x, y; // X:Y values for move/resize operations
philpem@5 8988 char *c; // Char values for window title
philpem@5 8989 bool createFullScreenWindow; // Boolean value used for full-screen window creation
philpem@5 8990 bool createClosedWindow; // Boolean value used for closed-window creation
philpem@5 8991 bool update; // Boolean value used for resize
philpem@5 8992 bool success; // Succes or failure of the message, used as return value
philpem@5 8993 CbSerializedQuery(CImgDisplay *s, CImgCarbonQueryKind k):sender(s),kind(k),success(false) {};
philpem@5 8994
philpem@5 8995 inline static CbSerializedQuery BuildReleaseWindowQuery(CImgDisplay* sender) {
philpem@5 8996 return CbSerializedQuery(sender, COM_RELEASEWINDOW);
philpem@5 8997 }
philpem@5 8998 inline static CbSerializedQuery BuildCreateWindowQuery(CImgDisplay* sender, const bool fullscreen, const bool closed) {
philpem@5 8999 CbSerializedQuery q(sender, COM_CREATEWINDOW);
philpem@5 9000 q.createFullScreenWindow = fullscreen;
philpem@5 9001 q.createClosedWindow = closed;
philpem@5 9002 return q;
philpem@5 9003 }
philpem@5 9004 inline static CbSerializedQuery BuildShowWindowQuery(CImgDisplay* sender) {
philpem@5 9005 return CbSerializedQuery(sender, COM_SHOWWINDOW);
philpem@5 9006 }
philpem@5 9007 inline static CbSerializedQuery BuildHideWindowQuery(CImgDisplay* sender) {
philpem@5 9008 return CbSerializedQuery(sender, COM_HIDEWINDOW);
philpem@5 9009 }
philpem@5 9010 inline static CbSerializedQuery BuildShowMouseQuery(CImgDisplay* sender) {
philpem@5 9011 return CbSerializedQuery(sender, COM_SHOWMOUSE);
philpem@5 9012 }
philpem@5 9013 inline static CbSerializedQuery BuildHideMouseQuery(CImgDisplay* sender) {
philpem@5 9014 return CbSerializedQuery(sender, COM_HIDEMOUSE);
philpem@5 9015 }
philpem@5 9016 inline static CbSerializedQuery BuildResizeWindowQuery(CImgDisplay* sender, const int x, const int y, bool update) {
philpem@5 9017 CbSerializedQuery q(sender, COM_RESIZEWINDOW);
philpem@5 9018 q.x = x, q.y = y;
philpem@5 9019 q.update = update;
philpem@5 9020 return q;
philpem@5 9021 }
philpem@5 9022 inline static CbSerializedQuery BuildMoveWindowQuery(CImgDisplay* sender, const int x, const int y) {
philpem@5 9023 CbSerializedQuery q(sender, COM_MOVEWINDOW);
philpem@5 9024 q.x = x, q.y = y;
philpem@5 9025 return q;
philpem@5 9026 }
philpem@5 9027 inline static CbSerializedQuery BuildSetWindowTitleQuery(CImgDisplay* sender, char* c) {
philpem@5 9028 CbSerializedQuery q(sender, COM_SETTITLE);
philpem@5 9029 q.c = c;
philpem@5 9030 return q;
philpem@5 9031 }
philpem@5 9032 inline static CbSerializedQuery BuildSetWindowPosQuery(CImgDisplay* sender, const int x, const int y) {
philpem@5 9033 CbSerializedQuery q(sender, COM_SETMOUSEPOS);
philpem@5 9034 q.x = x, q.y = y;
philpem@5 9035 return q;
philpem@5 9036 }
philpem@5 9037 };
philpem@5 9038
philpem@5 9039 // Send a serialized query in a synchroneous way.
philpem@5 9040 // @param c Application Carbon global settings.
philpem@5 9041 // @param m The query to send.
philpem@5 9042 // @result Success/failure of the operation returned by the event thread.
philpem@5 9043 bool _CbSendMsg(cimg::CarbonInfo& c, CbSerializedQuery m) {
philpem@5 9044 MPNotifyQueue(c.com_queue,&m,0,0); // Send the given message
philpem@5 9045 MPWaitOnSemaphore(c.sync_event,kDurationForever); // Wait end of processing notification
philpem@5 9046 return m.success;
philpem@5 9047 }
philpem@5 9048
philpem@5 9049 // Free the window attached to the current display.
philpem@5 9050 // @param c Application Carbon global settings.
philpem@5 9051 // @result Success/failure of the operation.
philpem@5 9052 bool _CbFreeAttachedWindow(cimg::CarbonInfo& c) {
philpem@5 9053 if (!_CbSendMsg(c, CbSerializedQuery::BuildReleaseWindowQuery(this))) // Ask the main thread to free the given window
philpem@5 9054 throw CImgDisplayException("Cannot release window associated with the current display.");
philpem@5 9055 // If a window existed, ask to release it
philpem@5 9056 MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
philpem@5 9057 --c.windowCount; //Decrement the window count
philpem@5 9058 MPExitCriticalRegion(c.windowListCR); // Unlock the list
philpem@5 9059 return c.windowCount == 0;
philpem@5 9060 }
philpem@5 9061
philpem@5 9062 // Create the window attached to the current display.
philpem@5 9063 // @param c Application Carbon global settings.
philpem@5 9064 // @param title The window title, if any.
philpem@5 9065 // @param fullscreen Shoud we start in fullscreen mode ?
philpem@5 9066 // @param create_closed If true, the window is created but not displayed.
philpem@5 9067 // @result Success/failure of the operation.
philpem@5 9068 void _CbCreateAttachedWindow(cimg::CarbonInfo& c, const char* title, const bool fullscreen, const bool create_closed) {
philpem@5 9069 if (!_CbSendMsg(c,CbSerializedQuery::BuildCreateWindowQuery(this,fullscreen,create_closed))) // Ask the main thread to create the window
philpem@5 9070 throw CImgDisplayException("Cannot create the window associated with the current display.");
philpem@5 9071 if (title) set_title(title); // Set the title, if any
philpem@5 9072 // Now we can register the window
philpem@5 9073 MPEnterCriticalRegion(c.windowListCR,kDurationForever); // Lock the list of the windows
philpem@5 9074 ++c.windowCount; //Increment the window count
philpem@5 9075 MPExitCriticalRegion(c.windowListCR); // Unlock the list
philpem@5 9076 }
philpem@5 9077
philpem@5 9078 // Destroy graphic objects previously allocated. We free the image, the data provider, then the colorspace.
philpem@5 9079 void _CbFinalizeGraphics() {
philpem@5 9080 CGImageRelease (imageRef); // Release the picture
philpem@5 9081 CGDataProviderRelease(dataProvider); // Release the DP
philpem@5 9082 CGColorSpaceRelease(csr); // Free the cs
philpem@5 9083 }
philpem@5 9084
philpem@5 9085 // Create graphic objects associated to a display. We have to create a colormap, a data provider, and the image.
philpem@5 9086 void _CbInitializeGraphics() {
philpem@5 9087 csr = CGColorSpaceCreateDeviceRGB(); // Create the color space first
philpem@5 9088 if (!csr)
philpem@5 9089 throw CImgDisplayException("CGColorSpaceCreateDeviceRGB() failed.");
philpem@5 9090 // Create the DP
philpem@5 9091 dataProvider = CGDataProviderCreateWithData(0,data,height*width*sizeof(unsigned int),0);
philpem@5 9092 if (!dataProvider)
philpem@5 9093 throw CImgDisplayException("CGDataProviderCreateWithData() failed.");
philpem@5 9094 // ... and finally the image.
philpem@5 9095 if (cimg::endianness())
philpem@5 9096 imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
philpem@5 9097 kCGImageAlphaNoneSkipFirst,dataProvider,0,false,kCGRenderingIntentDefault);
philpem@5 9098 else
philpem@5 9099 imageRef = CGImageCreate(width,height,8,32,width*sizeof(unsigned int),csr,
philpem@5 9100 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,dataProvider,0,false,kCGRenderingIntentDefault);
philpem@5 9101 if (!imageRef)
philpem@5 9102 throw CImgDisplayException("CGImageCreate() failed.");
philpem@5 9103 }
philpem@5 9104
philpem@5 9105 // Reinit graphic objects. Free them, then reallocate all.
philpem@5 9106 // This is used when image bounds are changed or when data source get invalid.
philpem@5 9107 void _CbReinitGraphics() {
philpem@5 9108 MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
philpem@5 9109 _CbFinalizeGraphics();
philpem@5 9110 _CbInitializeGraphics();
philpem@5 9111 MPExitCriticalRegion(paintCriticalRegion);
philpem@5 9112 }
philpem@5 9113
philpem@5 9114 // Convert a point having global coordonates into the window coordonates.
philpem@5 9115 // We use this function to replace the deprecated GlobalToLocal QuickDraw API.
philpem@5 9116 // @param mouseEvent The mouse event which triggered the event handler.
philpem@5 9117 // @param window The window where the event occured.
philpem@5 9118 // @param point The modified point struct.
philpem@5 9119 // @result True if the point struct has been converted successfully.
philpem@5 9120 static bool _CbToLocalPointFromMouseEvent(EventRef mouseEvent, WindowRef window, HIPoint* point) {
philpem@5 9121 Rect bounds;
philpem@5 9122 if (GetWindowBounds(window,kWindowStructureRgn,&bounds)==noErr) {
philpem@5 9123 point->x -= bounds.left;
philpem@5 9124 point->y -= bounds.top;
philpem@5 9125 HIViewRef view = NULL;
philpem@5 9126 if (HIViewGetViewForMouseEvent(HIViewGetRoot(window),mouseEvent,&view)==noErr)
philpem@5 9127 return HIViewConvertPoint(point, NULL, view) == noErr;
philpem@5 9128 }
philpem@5 9129 return false;
philpem@5 9130 }
philpem@5 9131
philpem@5 9132 static int screen_dimx() {
philpem@5 9133 return CGDisplayPixelsWide(kCGDirectMainDisplay);
philpem@5 9134 }
philpem@5 9135
philpem@5 9136 static int screen_dimy() {
philpem@5 9137 return CGDisplayPixelsHigh(kCGDirectMainDisplay);
philpem@5 9138 }
philpem@5 9139
philpem@5 9140 CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0,
philpem@5 9141 const unsigned int normalization_type=3,
philpem@5 9142 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 9143 if (!dimw || !dimh) return assign();
philpem@5 9144 _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 9145 min = max = 0;
philpem@5 9146 cimg_std::memset(data,0,sizeof(unsigned int)*width*height);
philpem@5 9147 return paint();
philpem@5 9148 }
philpem@5 9149
philpem@5 9150 template<typename T>
philpem@5 9151 CImgDisplay& assign(const CImg<T>& img, const char *title=0,
philpem@5 9152 const unsigned int normalization_type=3,
philpem@5 9153 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 9154 if (!img) return assign();
philpem@5 9155 CImg<T> tmp;
philpem@5 9156 const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 9157 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 9158 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 9159 return display(nimg);
philpem@5 9160 }
philpem@5 9161
philpem@5 9162 template<typename T>
philpem@5 9163 CImgDisplay& assign(const CImgList<T>& list, const char *title=0,
philpem@5 9164 const unsigned int normalization_type=3,
philpem@5 9165 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 9166 if (!list) return assign();
philpem@5 9167 CImg<T> tmp;
philpem@5 9168 const CImg<T> img = list.get_append('x','p'),
philpem@5 9169 &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 9170 _assign(nimg.width,nimg.height,title,normalization_type,fullscreen_flag,closed_flag);
philpem@5 9171 if (normalization==2) min = (float)nimg.minmax(max);
philpem@5 9172 return display(nimg);
philpem@5 9173 }
philpem@5 9174
philpem@5 9175 CImgDisplay& assign(const CImgDisplay &win) {
philpem@5 9176 if (!win) return assign();
philpem@5 9177 _assign(win.width,win.height,win.title,win.normalization,win.is_fullscreen,win.is_closed);
philpem@5 9178 cimg_std::memcpy(data,win.data,sizeof(unsigned int)*width*height);
philpem@5 9179 return paint();
philpem@5 9180 }
philpem@5 9181
philpem@5 9182 template<typename T>
philpem@5 9183 CImgDisplay& display(const CImg<T>& img) {
philpem@5 9184 if (is_empty()) assign(img.width,img.height);
philpem@5 9185 return render(img).paint();
philpem@5 9186 }
philpem@5 9187
philpem@5 9188 CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) {
philpem@5 9189 if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign();
philpem@5 9190 if (is_empty()) return assign(nwidth,nheight);
philpem@5 9191 const unsigned int
philpem@5 9192 tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100),
philpem@5 9193 tmpdimy = (nheight>0)?nheight:(-nheight*height/100),
philpem@5 9194 dimx = tmpdimx?tmpdimx:1,
philpem@5 9195 dimy = tmpdimy?tmpdimy:1;
philpem@5 9196 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9197
philpem@5 9198 if ((window_width!=dimx || window_height!=dimy) &&
philpem@5 9199 !_CbSendMsg(c,CbSerializedQuery::BuildResizeWindowQuery(this,dimx,dimy,redraw)))
philpem@5 9200 throw CImgDisplayException("CImgDisplay::resize() : Cannot resize the window associated to the current display.");
philpem@5 9201
philpem@5 9202 if (width!=dimx || height!=dimy) {
philpem@5 9203 unsigned int *ndata = new unsigned int[dimx*dimy];
philpem@5 9204 if (redraw) _render_resize(data,width,height,ndata,dimx,dimy);
philpem@5 9205 else cimg_std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy);
philpem@5 9206 unsigned int const* old_data = data;
philpem@5 9207 data = ndata;
philpem@5 9208 delete[] old_data;
philpem@5 9209 _CbReinitGraphics();
philpem@5 9210 }
philpem@5 9211 window_width = width = dimx; window_height = height = dimy;
philpem@5 9212 is_resized = false;
philpem@5 9213 if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2);
philpem@5 9214 if (redraw) return paint();
philpem@5 9215 return *this;
philpem@5 9216 }
philpem@5 9217
philpem@5 9218 CImgDisplay& move(const int posx, const int posy) {
philpem@5 9219 if (is_empty()) return *this;
philpem@5 9220 if (!is_fullscreen) {
philpem@5 9221 // If the operation succeeds, window_x and window_y are updated by the event thread
philpem@5 9222 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9223 // Send the query
philpem@5 9224 if (!_CbSendMsg(c,CbSerializedQuery::BuildMoveWindowQuery(this,posx,posy)))
philpem@5 9225 throw CImgDisplayException("CImgDisplay::move() : Cannot move the window associated to the current display.");
philpem@5 9226 }
philpem@5 9227 return show();
philpem@5 9228 }
philpem@5 9229
philpem@5 9230 CImgDisplay& set_mouse(const int posx, const int posy) {
philpem@5 9231 if (!is_closed && posx>=0 && posy>=0) {
philpem@5 9232 // If the operation succeeds, mouse_x and mouse_y are updated by the event thread
philpem@5 9233 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9234 // Send the query
philpem@5 9235 if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowPosQuery(this,posx,posy)))
philpem@5 9236 throw CImgDisplayException("CImgDisplay::set_mouse() : Cannot set the mouse position to the current display.");
philpem@5 9237 }
philpem@5 9238 return *this;
philpem@5 9239 }
philpem@5 9240
philpem@5 9241 CImgDisplay& hide_mouse() {
philpem@5 9242 if (is_empty()) return *this;
philpem@5 9243 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9244 // Send the query
philpem@5 9245 if (!_CbSendMsg(c,CbSerializedQuery::BuildHideMouseQuery(this)))
philpem@5 9246 throw CImgDisplayException("CImgDisplay::hide_mouse() : Cannot hide the mouse associated to the current display.");
philpem@5 9247 return *this;
philpem@5 9248 }
philpem@5 9249
philpem@5 9250 CImgDisplay& show_mouse() {
philpem@5 9251 if (is_empty()) return *this;
philpem@5 9252 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9253 // Send the query
philpem@5 9254 if (!_CbSendMsg(c,CbSerializedQuery::BuildShowMouseQuery(this)))
philpem@5 9255 throw CImgDisplayException("CImgDisplay::show_mouse() : Cannot show the mouse associated to the current display.");
philpem@5 9256 return *this;
philpem@5 9257 }
philpem@5 9258
philpem@5 9259 static void wait_all() {
philpem@5 9260 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9261 MPWaitOnSemaphore(c.wait_event,kDurationForever);
philpem@5 9262 }
philpem@5 9263
philpem@5 9264 CImgDisplay& show() {
philpem@5 9265 if (is_empty()) return *this;
philpem@5 9266 if (is_closed) {
philpem@5 9267 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9268 if (!_CbSendMsg(c,CbSerializedQuery::BuildShowWindowQuery(this)))
philpem@5 9269 throw CImgDisplayException("CImgDisplay::show() : Cannot show the window associated to the current display.");
philpem@5 9270 }
philpem@5 9271 return paint();
philpem@5 9272 }
philpem@5 9273
philpem@5 9274 CImgDisplay& close() {
philpem@5 9275 if (is_empty()) return *this;
philpem@5 9276 if (!is_closed && !is_fullscreen) {
philpem@5 9277 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9278 // If the operation succeeds, window_x and window_y are updated on the event thread
philpem@5 9279 if (!_CbSendMsg(c,CbSerializedQuery::BuildHideWindowQuery(this)))
philpem@5 9280 throw CImgDisplayException("CImgDisplay::close() : Cannot hide the window associated to the current display.");
philpem@5 9281 }
philpem@5 9282 return *this;
philpem@5 9283 }
philpem@5 9284
philpem@5 9285 CImgDisplay& set_title(const char *format, ...) {
philpem@5 9286 if (is_empty()) return *this;
philpem@5 9287 char tmp[1024] = {0};
philpem@5 9288 va_list ap;
philpem@5 9289 va_start(ap, format);
philpem@5 9290 cimg_std::vsprintf(tmp,format,ap);
philpem@5 9291 va_end(ap);
philpem@5 9292 if (title) delete[] title;
philpem@5 9293 const int s = cimg::strlen(tmp)+1;
philpem@5 9294 title = new char[s];
philpem@5 9295 cimg_std::memcpy(title,tmp,s*sizeof(char));
philpem@5 9296 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9297 if (!_CbSendMsg(c,CbSerializedQuery::BuildSetWindowTitleQuery(this,tmp)))
philpem@5 9298 throw CImgDisplayException("CImgDisplay::set_title() : Cannot set the window title associated to the current display.");
philpem@5 9299 return *this;
philpem@5 9300 }
philpem@5 9301
philpem@5 9302 CImgDisplay& paint() {
philpem@5 9303 if (!is_closed) {
philpem@5 9304 MPEnterCriticalRegion(paintCriticalRegion,kDurationForever);
philpem@5 9305 CGrafPtr portPtr = GetWindowPort(carbonWindow);
philpem@5 9306 CGContextRef currentContext = 0;
philpem@5 9307 QDBeginCGContext(portPtr,&currentContext);
philpem@5 9308 CGContextSetRGBFillColor(currentContext,255,255,255,255);
philpem@5 9309 CGContextFillRect(currentContext,CGRectMake(0,0,window_width,window_height));
philpem@5 9310 CGContextDrawImage(currentContext,CGRectMake(0,int(window_height-height)<0?0:window_height-height,width,height),imageRef);
philpem@5 9311 CGContextFlush(currentContext);
philpem@5 9312 QDEndCGContext(portPtr, &currentContext);
philpem@5 9313 MPExitCriticalRegion(paintCriticalRegion);
philpem@5 9314 }
philpem@5 9315 return *this;
philpem@5 9316 }
philpem@5 9317
philpem@5 9318 template<typename T>
philpem@5 9319 CImgDisplay& render(const CImg<T>& img) {
philpem@5 9320 if (is_empty()) return *this;
philpem@5 9321 if (!img)
philpem@5 9322 throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.",
philpem@5 9323 img.width,img.height,img.depth,img.dim,img.data);
philpem@5 9324 if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2));
philpem@5 9325 const T
philpem@5 9326 *data1 = img.data,
philpem@5 9327 *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1,
philpem@5 9328 *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1;
philpem@5 9329 MPEnterCriticalRegion(paintCriticalRegion, kDurationForever);
philpem@5 9330 unsigned int
philpem@5 9331 *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height],
philpem@5 9332 *ptrd = ndata;
philpem@5 9333 if (!normalization || (normalization==3 && cimg::type<T>::string()==cimg::type<unsigned char>::string())) {
philpem@5 9334 min = max = 0;
philpem@5 9335 for (unsigned int xy = img.width*img.height; xy>0; --xy)
philpem@5 9336 *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++);
philpem@5 9337 } else {
philpem@5 9338 if (normalization==3) {
philpem@5 9339 if (cimg::type<T>::is_float()) min = (float)img.minmax(max);
philpem@5 9340 else {
philpem@5 9341 min = (float)cimg::type<T>::min();
philpem@5 9342 max = (float)cimg::type<T>::max();
philpem@5 9343 }
philpem@5 9344 } else if ((min>max) || normalization==1) min = (float)img.minmax(max);
philpem@5 9345 const float delta = max-min, mm = delta?delta:1.0f;
philpem@5 9346 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 9347 const unsigned char
philpem@5 9348 R = (unsigned char)(255*(*(data1++)-min)/mm),
philpem@5 9349 G = (unsigned char)(255*(*(data2++)-min)/mm),
philpem@5 9350 B = (unsigned char)(255*(*(data3++)-min)/mm);
philpem@5 9351 *(ptrd++) = (R<<16) | (G<<8) | (B);
philpem@5 9352 }
philpem@5 9353 }
philpem@5 9354 if (ndata!=data) {
philpem@5 9355 _render_resize(ndata,img.width,img.height,data,width,height);
philpem@5 9356 delete[] ndata;
philpem@5 9357 }
philpem@5 9358 MPExitCriticalRegion(paintCriticalRegion);
philpem@5 9359 return *this;
philpem@5 9360 }
philpem@5 9361
philpem@5 9362 template<typename T>
philpem@5 9363 const CImgDisplay& snapshot(CImg<T>& img) const {
philpem@5 9364 if (is_empty()) img.assign();
philpem@5 9365 else {
philpem@5 9366 img.assign(width,height,1,3);
philpem@5 9367 T
philpem@5 9368 *data1 = img.ptr(0,0,0,0),
philpem@5 9369 *data2 = img.ptr(0,0,0,1),
philpem@5 9370 *data3 = img.ptr(0,0,0,2);
philpem@5 9371 unsigned int *ptrs = data;
philpem@5 9372 for (unsigned int xy = img.width*img.height; xy>0; --xy) {
philpem@5 9373 const unsigned int val = *(ptrs++);
philpem@5 9374 *(data1++) = (unsigned char)(val>>16);
philpem@5 9375 *(data2++) = (unsigned char)((val>>8)&0xFF);
philpem@5 9376 *(data3++) = (unsigned char)(val&0xFF);
philpem@5 9377 }
philpem@5 9378 }
philpem@5 9379 return *this;
philpem@5 9380 }
philpem@5 9381
philpem@5 9382 CImgDisplay& toggle_fullscreen(const bool redraw=true) {
philpem@5 9383 if (is_empty()) return *this;
philpem@5 9384 if (redraw) {
philpem@5 9385 const unsigned int bufsize = width*height*4;
philpem@5 9386 void *odata = cimg_std::malloc(bufsize);
philpem@5 9387 cimg_std::memcpy(odata,data,bufsize);
philpem@5 9388 assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 9389 cimg_std::memcpy(data,odata,bufsize);
philpem@5 9390 cimg_std::free(odata);
philpem@5 9391 return paint();
philpem@5 9392 }
philpem@5 9393 return assign(width,height,title,normalization,!is_fullscreen,false);
philpem@5 9394 }
philpem@5 9395
philpem@5 9396 static OSStatus CarbonEventHandler(EventHandlerCallRef myHandler, EventRef theEvent, void* userData) {
philpem@5 9397 OSStatus result = eventNotHandledErr;
philpem@5 9398 CImgDisplay* disp = (CImgDisplay*) userData;
philpem@5 9399 (void)myHandler; // Avoid "unused parameter"
philpem@5 9400 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9401 // Gets the associated display
philpem@5 9402 if (disp) {
philpem@5 9403 // Window events are always handled
philpem@5 9404 if (GetEventClass(theEvent)==kEventClassWindow) switch (GetEventKind (theEvent)) {
philpem@5 9405 case kEventWindowClose :
philpem@5 9406 disp->mouse_x = disp->mouse_y = -1;
philpem@5 9407 disp->window_x = disp->window_y = 0;
philpem@5 9408 if (disp->button) {
philpem@5 9409 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 9410 disp->button = 0;
philpem@5 9411 }
philpem@5 9412 if (disp->key) {
philpem@5 9413 cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
philpem@5 9414 disp->key = 0;
philpem@5 9415 }
philpem@5 9416 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
philpem@5 9417 disp->is_closed = true;
philpem@5 9418 HideWindow(disp->carbonWindow);
philpem@5 9419 disp->is_event = true;
philpem@5 9420 MPSignalSemaphore(c.wait_event);
philpem@5 9421 result = noErr;
philpem@5 9422 break;
philpem@5 9423 // There is a lot of case where we have to redraw our window
philpem@5 9424 case kEventWindowBoundsChanging :
philpem@5 9425 case kEventWindowResizeStarted :
philpem@5 9426 case kEventWindowCollapsed : //Not sure it's really needed :-)
philpem@5 9427 break;
philpem@5 9428 case kEventWindowZoomed :
philpem@5 9429 case kEventWindowExpanded :
philpem@5 9430 case kEventWindowResizeCompleted : {
philpem@5 9431 MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
philpem@5 9432 // Now we retrieve the new size of the window
philpem@5 9433 Rect newContentRect;
philpem@5 9434 GetWindowBounds(disp->carbonWindow,kWindowContentRgn,&newContentRect);
philpem@5 9435 const unsigned int
philpem@5 9436 nw = (unsigned int)(newContentRect.right - newContentRect.left),
philpem@5 9437 nh = (unsigned int)(newContentRect.bottom - newContentRect.top);
philpem@5 9438
philpem@5 9439 // Then we update CImg internal settings
philpem@5 9440 if (nw && nh && (nw!=disp->width || nh!=disp->height)) {
philpem@5 9441 disp->window_width = nw;
philpem@5 9442 disp->window_height = nh;
philpem@5 9443 disp->mouse_x = disp->mouse_y = -1;
philpem@5 9444 disp->is_resized = true;
philpem@5 9445 }
philpem@5 9446 disp->is_event = true;
philpem@5 9447 MPExitCriticalRegion(disp->paintCriticalRegion);
philpem@5 9448 disp->paint(); // Coords changed, must update the screen
philpem@5 9449 MPSignalSemaphore(c.wait_event);
philpem@5 9450 result = noErr;
philpem@5 9451 } break;
philpem@5 9452 case kEventWindowDragStarted :
philpem@5 9453 case kEventWindowDragCompleted : {
philpem@5 9454 MPEnterCriticalRegion(disp->paintCriticalRegion, kDurationForever);
philpem@5 9455 // Now we retrieve the new size of the window
philpem@5 9456 Rect newContentRect ;
philpem@5 9457 GetWindowBounds(disp->carbonWindow,kWindowStructureRgn,&newContentRect);
philpem@5 9458 const int nx = (int)(newContentRect.left), ny = (int)(newContentRect.top);
philpem@5 9459 // Then we update CImg internal settings
philpem@5 9460 if (nx!=disp->window_x || ny!=disp->window_y) {
philpem@5 9461 disp->window_x = nx;
philpem@5 9462 disp->window_y = ny;
philpem@5 9463 disp->is_moved = true;
philpem@5 9464 }
philpem@5 9465 disp->is_event = true;
philpem@5 9466 MPExitCriticalRegion(disp->paintCriticalRegion);
philpem@5 9467 disp->paint(); // Coords changed, must update the screen
philpem@5 9468 MPSignalSemaphore(c.wait_event);
philpem@5 9469 result = noErr;
philpem@5 9470 } break;
philpem@5 9471 case kEventWindowPaint :
philpem@5 9472 disp->paint();
philpem@5 9473 break;
philpem@5 9474 }
philpem@5 9475
philpem@5 9476 switch (GetEventClass(theEvent)) {
philpem@5 9477 case kEventClassKeyboard : {
philpem@5 9478 if (GetEventKind(theEvent)==kEventRawKeyModifiersChanged) {
philpem@5 9479 // Apple has special keys named "notifiers", we have to convert this (exotic ?) key handling into the regular CImg processing.
philpem@5 9480 UInt32 newModifiers;
philpem@5 9481 if (GetEventParameter(theEvent,kEventParamKeyModifiers,typeUInt32,0,sizeof(UInt32),0,&newModifiers)==noErr) {
philpem@5 9482 int newKeyCode = -1;
philpem@5 9483 UInt32 changed = disp->lastKeyModifiers^newModifiers;
philpem@5 9484 // Find what changed here
philpem@5 9485 if ((changed & rightShiftKey)!=0) newKeyCode = cimg::keySHIFTRIGHT;
philpem@5 9486 if ((changed & shiftKey)!=0) newKeyCode = cimg::keySHIFTLEFT;
philpem@5 9487
philpem@5 9488 // On the Mac, the "option" key = the ALT key
philpem@5 9489 if ((changed & (optionKey | rightOptionKey))!=0) newKeyCode = cimg::keyALTGR;
philpem@5 9490 if ((changed & controlKey)!=0) newKeyCode = cimg::keyCTRLLEFT;
philpem@5 9491 if ((changed & rightControlKey)!=0) newKeyCode = cimg::keyCTRLRIGHT;
philpem@5 9492 if ((changed & cmdKey)!=0) newKeyCode = cimg::keyAPPLEFT;
philpem@5 9493 if ((changed & alphaLock)!=0) newKeyCode = cimg::keyCAPSLOCK;
philpem@5 9494 if (newKeyCode != -1) { // Simulate keystroke
philpem@5 9495 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
philpem@5 9496 disp->key = (int)newKeyCode;
philpem@5 9497 }
philpem@5 9498 disp->lastKeyModifiers = newModifiers; // Save current state
philpem@5 9499 }
philpem@5 9500 disp->is_event = true;
philpem@5 9501 MPSignalSemaphore(c.wait_event);
philpem@5 9502 }
philpem@5 9503 if (GetEventKind(theEvent)==kEventRawKeyDown || GetEventKind(theEvent)==kEventRawKeyRepeat) {
philpem@5 9504 char keyCode;
philpem@5 9505 if (GetEventParameter(theEvent,kEventParamKeyMacCharCodes,typeChar,0,sizeof(keyCode),0,&keyCode)==noErr) {
philpem@5 9506 disp->update_iskey((unsigned int)keyCode,true);
philpem@5 9507 if (disp->key) cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1);
philpem@5 9508 disp->key = (unsigned int)keyCode;
philpem@5 9509 if (disp->released_key) { cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1); disp->released_key = 0; }
philpem@5 9510 }
philpem@5 9511 disp->is_event = true;
philpem@5 9512 MPSignalSemaphore(c.wait_event);
philpem@5 9513 }
philpem@5 9514 } break;
philpem@5 9515
philpem@5 9516 case kEventClassMouse :
philpem@5 9517 switch (GetEventKind(theEvent)) {
philpem@5 9518 case kEventMouseDragged :
philpem@5 9519 // When you push the main button on the Apple mouse while moving it, you got NO kEventMouseMoved msg,
philpem@5 9520 // but a kEventMouseDragged one. So we merge them here.
philpem@5 9521 case kEventMouseMoved :
philpem@5 9522 HIPoint point;
philpem@5 9523 if (GetEventParameter(theEvent,kEventParamMouseLocation,typeHIPoint,0,sizeof(point),0,&point)==noErr) {
philpem@5 9524 if (_CbToLocalPointFromMouseEvent(theEvent,disp->carbonWindow,&point)) {
philpem@5 9525 disp->mouse_x = (int)point.x;
philpem@5 9526 disp->mouse_y = (int)point.y;
philpem@5 9527 if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy())
philpem@5 9528 disp->mouse_x = disp->mouse_y = -1;
philpem@5 9529 } else disp->mouse_x = disp->mouse_y = -1;
philpem@5 9530 }
philpem@5 9531 disp->is_event = true;
philpem@5 9532 MPSignalSemaphore(c.wait_event);
philpem@5 9533 break;
philpem@5 9534 case kEventMouseDown :
philpem@5 9535 UInt16 btn;
philpem@5 9536 if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
philpem@5 9537 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 9538 if (btn==kEventMouseButtonPrimary) disp->button|=1U;
philpem@5 9539 // For those who don't have a multi-mouse button (as me), I think it's better to allow the user
philpem@5 9540 // to emulate a right click by using the Control key
philpem@5 9541 if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
philpem@5 9542 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Down]");
philpem@5 9543 if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button|=2U;
philpem@5 9544 if (btn==kEventMouseButtonTertiary) disp->button|=4U;
philpem@5 9545 }
philpem@5 9546 disp->is_event = true;
philpem@5 9547 MPSignalSemaphore(c.wait_event);
philpem@5 9548 break;
philpem@5 9549 case kEventMouseWheelMoved :
philpem@5 9550 EventMouseWheelAxis wheelax;
philpem@5 9551 SInt32 delta;
philpem@5 9552 if (GetEventParameter(theEvent,kEventParamMouseWheelAxis,typeMouseWheelAxis,0,sizeof(wheelax),0,&wheelax)==noErr)
philpem@5 9553 if (wheelax==kEventMouseWheelAxisY) {
philpem@5 9554 if (GetEventParameter(theEvent,kEventParamMouseWheelDelta,typeLongInteger,0,sizeof(delta),0,&delta)==noErr)
philpem@5 9555 if (delta>0) disp->wheel+=delta/120; //FIXME: why 120 ?
philpem@5 9556 disp->is_event = true;
philpem@5 9557 MPSignalSemaphore(c.wait_event);
philpem@5 9558 }
philpem@5 9559 break;
philpem@5 9560 }
philpem@5 9561 }
philpem@5 9562
philpem@5 9563 switch (GetEventClass(theEvent)) {
philpem@5 9564 case kEventClassKeyboard :
philpem@5 9565 if (GetEventKind(theEvent)==kEventRawKeyUp) {
philpem@5 9566 UInt32 keyCode;
philpem@5 9567 if (GetEventParameter(theEvent,kEventParamKeyCode,typeUInt32,0,sizeof(keyCode),0,&keyCode)==noErr) {
philpem@5 9568 disp->update_iskey((unsigned int)keyCode,false);
philpem@5 9569 if (disp->key) { cimg_std::memmove((void*)(disp->keys+1),(void*)disp->keys,512-1); disp->key = 0; }
philpem@5 9570 if (disp->released_key) cimg_std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,512-1);
philpem@5 9571 disp->released_key = (int)keyCode;
philpem@5 9572 }
philpem@5 9573 disp->is_event = true;
philpem@5 9574 MPSignalSemaphore(c.wait_event);
philpem@5 9575 }
philpem@5 9576 break;
philpem@5 9577
philpem@5 9578 case kEventClassMouse :
philpem@5 9579 switch (GetEventKind(theEvent)) {
philpem@5 9580 case kEventMouseUp :
philpem@5 9581 UInt16 btn;
philpem@5 9582 if (GetEventParameter(theEvent,kEventParamMouseButton,typeMouseButton,0,sizeof(btn),0,&btn)==noErr) {
philpem@5 9583 cimg_std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,512-1);
philpem@5 9584 if (btn==kEventMouseButtonPrimary) disp->button&=~1U;
philpem@5 9585 // See note in kEventMouseDown handler.
philpem@5 9586 if ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)
philpem@5 9587 cimg::warn("CImgDisplay::CarbonEventHandler() : Will emulate right click now [Up]");
philpem@5 9588 if (btn==kEventMouseButtonSecondary || ((disp->lastKeyModifiers & (controlKey | rightControlKey))!=0)) disp->button&=~2U;
philpem@5 9589 if (btn==kEventMouseButtonTertiary) disp->button&=~2U;
philpem@5 9590 }
philpem@5 9591 disp->is_event = true;
philpem@5 9592 MPSignalSemaphore(c.wait_event);
philpem@5 9593 break;
philpem@5 9594 }
philpem@5 9595 }
philpem@5 9596 }
philpem@5 9597 return (result);
philpem@5 9598 }
philpem@5 9599
philpem@5 9600 static void* _events_thread(void* args) {
philpem@5 9601 (void)args; // Make the compiler happy
philpem@5 9602 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9603 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0);
philpem@5 9604 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0);
philpem@5 9605 MPSignalSemaphore(c.sync_event); // Notify the caller that all goes fine
philpem@5 9606 EventRef theEvent;
philpem@5 9607 EventTargetRef theTarget;
philpem@5 9608 OSStatus err;
philpem@5 9609 CbSerializedQuery* query;
philpem@5 9610 theTarget = GetEventDispatcherTarget();
philpem@5 9611
philpem@5 9612 // Enter in the main loop
philpem@5 9613 while (true) {
philpem@5 9614 pthread_testcancel(); /* Check if cancelation happens */
philpem@5 9615 err = ReceiveNextEvent(0,0,kDurationImmediate,true,&theEvent); // Fetch new events
philpem@5 9616 if (err==noErr) { // Received a carbon event, so process it !
philpem@5 9617 SendEventToEventTarget (theEvent, theTarget);
philpem@5 9618 ReleaseEvent(theEvent);
philpem@5 9619 } else if (err == eventLoopTimedOutErr) { // There is no event to process, so check if there is new messages to process
philpem@5 9620 OSStatus r =MPWaitOnQueue(c.com_queue,(void**)&query,0,0,10*kDurationMillisecond);
philpem@5 9621 if (r!=noErr) continue; //nothing in the queue or an error.., bye
philpem@5 9622 // If we're here, we've something to do now.
philpem@5 9623 if (query) {
philpem@5 9624 switch (query->kind) {
philpem@5 9625 case COM_SETMOUSEPOS : { // change the cursor position
philpem@5 9626 query->success = CGDisplayMoveCursorToPoint(kCGDirectMainDisplay,CGPointMake(query->sender->window_x+query->x,query->sender->window_y+query->y))
philpem@5 9627 == kCGErrorSuccess;
philpem@5 9628 if (query->success) {
philpem@5 9629 query->sender->mouse_x = query->x;
philpem@5 9630 query->sender->mouse_y = query->y;
philpem@5 9631 } else cimg::warn("CImgDisplay::_events_thread() : CGDisplayMoveCursorToPoint failed.");
philpem@5 9632 } break;
philpem@5 9633 case COM_SETTITLE : { // change the title bar caption
philpem@5 9634 CFStringRef windowTitle = CFStringCreateWithCString(0,query->c,kCFStringEncodingMacRoman);
philpem@5 9635 query->success = SetWindowTitleWithCFString(query->sender->carbonWindow,windowTitle)==noErr;
philpem@5 9636 if (!query->success)
philpem@5 9637 cimg::warn("CImgDisplay::_events_thread() : SetWindowTitleWithCFString failed.");
philpem@5 9638 CFRelease(windowTitle);
philpem@5 9639 } break;
philpem@5 9640 case COM_RESIZEWINDOW : { // Resize a window
philpem@5 9641 SizeWindow(query->sender->carbonWindow,query->x,query->y,query->update);
philpem@5 9642 // If the window has been resized successfully, update display informations
philpem@5 9643 query->sender->window_width = query->x;
philpem@5 9644 query->sender->window_height = query->y;
philpem@5 9645 query->success = true;
philpem@5 9646 } break;
philpem@5 9647 case COM_MOVEWINDOW : { // Move a window
philpem@5 9648 MoveWindow(query->sender->carbonWindow,query->x,query->y,false);
philpem@5 9649 query->sender->window_x = query->x;
philpem@5 9650 query->sender->window_y = query->y;
philpem@5 9651 query->sender->is_moved = false;
philpem@5 9652 query->success = true;
philpem@5 9653 } break;
philpem@5 9654 case COM_SHOWMOUSE : { // Show the mouse
philpem@5 9655 query->success = CGDisplayShowCursor(kCGDirectMainDisplay)==noErr;
philpem@5 9656 if (!query->success)
philpem@5 9657 cimg::warn("CImgDisplay::_events_thread() : CGDisplayShowCursor failed.");
philpem@5 9658 } break;
philpem@5 9659 case COM_HIDEMOUSE : { // Hide the mouse
philpem@5 9660 query->success = CGDisplayHideCursor(kCGDirectMainDisplay)==noErr;
philpem@5 9661 if (!query->success)
philpem@5 9662 cimg::warn("CImgDisplay::_events_thread() : CGDisplayHideCursor failed.");
philpem@5 9663 } break;
philpem@5 9664 case COM_SHOWWINDOW : { // We've to show a window
philpem@5 9665 ShowWindow(query->sender->carbonWindow);
philpem@5 9666 query->success = true;
philpem@5 9667 query->sender->is_closed = false;
philpem@5 9668 } break;
philpem@5 9669 case COM_HIDEWINDOW : { // We've to show a window
philpem@5 9670 HideWindow(query->sender->carbonWindow);
philpem@5 9671 query->sender->is_closed = true;
philpem@5 9672 query->sender->window_x = query->sender->window_y = 0;
philpem@5 9673 query->success = true;
philpem@5 9674 } break;
philpem@5 9675 case COM_RELEASEWINDOW : { // We have to release a given window handle
philpem@5 9676 query->success = true;
philpem@5 9677 CFRelease(query->sender->carbonWindow);
philpem@5 9678 } break;
philpem@5 9679 case COM_CREATEWINDOW : { // We have to create a window
philpem@5 9680 query->success = true;
philpem@5 9681 WindowAttributes windowAttrs;
philpem@5 9682 Rect contentRect;
philpem@5 9683 if (query->createFullScreenWindow) {
philpem@5 9684 // To simulate a "true" full screen, we remove menus and close boxes
philpem@5 9685 windowAttrs = (1L << 9); //Why ? kWindowNoTitleBarAttribute seems to be not defined on 10.3
philpem@5 9686 // Define a full screen bound rect
philpem@5 9687 SetRect(&contentRect,0,0,CGDisplayPixelsWide(kCGDirectMainDisplay),CGDisplayPixelsHigh(kCGDirectMainDisplay));
philpem@5 9688 } else { // Set the window size
philpem@5 9689 SetRect(&contentRect,0,0,query->sender->width,query->sender->height); // Window will be centered with RepositionWindow.
philpem@5 9690 // Use default attributes
philpem@5 9691 windowAttrs = kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute | kWindowLiveResizeAttribute;
philpem@5 9692 }
philpem@5 9693 // Update window position
philpem@5 9694 if (query->createClosedWindow) query->sender->window_x = query->sender->window_y = 0;
philpem@5 9695 else {
philpem@5 9696 query->sender->window_x = contentRect.left;
philpem@5 9697 query->sender->window_y = contentRect.top;
philpem@5 9698 }
philpem@5 9699 // Update window flags
philpem@5 9700 query->sender->window_width = query->sender->width;
philpem@5 9701 query->sender->window_height = query->sender->height;
philpem@5 9702 query->sender->flush();
philpem@5 9703 // Create the window
philpem@5 9704 if (CreateNewWindow(kDocumentWindowClass,windowAttrs,&contentRect,&query->sender->carbonWindow)!=noErr) {
philpem@5 9705 query->success = false;
philpem@5 9706 cimg::warn("CImgDisplay::_events_thread() : CreateNewWindow() failed.");
philpem@5 9707 }
philpem@5 9708 // Send it to the foreground
philpem@5 9709 if (RepositionWindow(query->sender->carbonWindow,0,kWindowCenterOnMainScreen)!=noErr) query->success = false;
philpem@5 9710 // Show it, if needed
philpem@5 9711 if (!query->createClosedWindow) ShowWindow(query->sender->carbonWindow);
philpem@5 9712
philpem@5 9713 // Associate a valid event handler
philpem@5 9714 EventTypeSpec eventList[] = {
philpem@5 9715 { kEventClassWindow, kEventWindowClose },
philpem@5 9716 { kEventClassWindow, kEventWindowResizeStarted },
philpem@5 9717 { kEventClassWindow, kEventWindowResizeCompleted },
philpem@5 9718 { kEventClassWindow, kEventWindowDragStarted},
philpem@5 9719 { kEventClassWindow, kEventWindowDragCompleted },
philpem@5 9720 { kEventClassWindow, kEventWindowPaint },
philpem@5 9721 { kEventClassWindow, kEventWindowBoundsChanging },
philpem@5 9722 { kEventClassWindow, kEventWindowCollapsed },
philpem@5 9723 { kEventClassWindow, kEventWindowExpanded },
philpem@5 9724 { kEventClassWindow, kEventWindowZoomed },
philpem@5 9725 { kEventClassKeyboard, kEventRawKeyDown },
philpem@5 9726 { kEventClassKeyboard, kEventRawKeyUp },
philpem@5 9727 { kEventClassKeyboard, kEventRawKeyRepeat },
philpem@5 9728 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
philpem@5 9729 { kEventClassMouse, kEventMouseMoved },
philpem@5 9730 { kEventClassMouse, kEventMouseDown },
philpem@5 9731 { kEventClassMouse, kEventMouseUp },
philpem@5 9732 { kEventClassMouse, kEventMouseDragged }
philpem@5 9733 };
philpem@5 9734
philpem@5 9735 // Set up the handler
philpem@5 9736 if (InstallWindowEventHandler(query->sender->carbonWindow,NewEventHandlerUPP(CarbonEventHandler),GetEventTypeCount(eventList),
philpem@5 9737 eventList,(void*)query->sender,0)!=noErr) {
philpem@5 9738 query->success = false;
philpem@5 9739 cimg::warn("CImgDisplay::_events_thread() : InstallWindowEventHandler failed.");
philpem@5 9740 }
philpem@5 9741
philpem@5 9742 // Paint
philpem@5 9743 query->sender->paint();
philpem@5 9744 } break;
philpem@5 9745 default :
philpem@5 9746 cimg::warn("CImgDisplay::_events_thread() : Received unknow code %d.",query->kind);
philpem@5 9747 }
philpem@5 9748 // Signal that the message has been processed
philpem@5 9749 MPSignalSemaphore(c.sync_event);
philpem@5 9750 }
philpem@5 9751 }
philpem@5 9752 }
philpem@5 9753 // If we are here, the application is now finished
philpem@5 9754 pthread_exit(0);
philpem@5 9755 }
philpem@5 9756
philpem@5 9757 CImgDisplay& assign() {
philpem@5 9758 if (is_empty()) return *this;
philpem@5 9759 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9760 // Destroy the window associated to the display
philpem@5 9761 _CbFreeAttachedWindow(c);
philpem@5 9762 // Don't destroy the background thread here.
philpem@5 9763 // If you check whether _CbFreeAttachedWindow() returned true,
philpem@5 9764 // - saying that there were no window left on screen - and
philpem@5 9765 // you destroy the background thread here, ReceiveNextEvent won't
philpem@5 9766 // work anymore if you create a new window after. So the
philpem@5 9767 // background thread must be killed (pthread_cancel() + pthread_join())
philpem@5 9768 // only on the application shutdown.
philpem@5 9769
philpem@5 9770 // Finalize graphics
philpem@5 9771 _CbFinalizeGraphics();
philpem@5 9772
philpem@5 9773 // Do some cleanup
philpem@5 9774 if (data) delete[] data;
philpem@5 9775 if (title) delete[] title;
philpem@5 9776 width = height = normalization = window_width = window_height = 0;
philpem@5 9777 window_x = window_y = 0;
philpem@5 9778 is_fullscreen = false;
philpem@5 9779 is_closed = true;
philpem@5 9780 min = max = 0;
philpem@5 9781 title = 0;
philpem@5 9782 flush();
philpem@5 9783 if (MPDeleteCriticalRegion(paintCriticalRegion)!=noErr)
philpem@5 9784 throw CImgDisplayException("CImgDisplay()::assign() : MPDeleteCriticalRegion failed.");
philpem@5 9785 return *this;
philpem@5 9786 }
philpem@5 9787
philpem@5 9788 CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0,
philpem@5 9789 const unsigned int normalization_type=3,
philpem@5 9790 const bool fullscreen_flag=false, const bool closed_flag=false) {
philpem@5 9791 cimg::CarbonInfo& c = cimg::CarbonAttr();
philpem@5 9792
philpem@5 9793 // Allocate space for window title
philpem@5 9794 const int s = cimg::strlen(ptitle)+1;
philpem@5 9795 char *tmp_title = s?new char[s]:0;
philpem@5 9796 if (s) cimg_std::memcpy(tmp_title,ptitle,s*sizeof(char));
philpem@5 9797
philpem@5 9798 // Destroy previous window if existing
philpem@5 9799 if (!is_empty()) assign();
philpem@5 9800
philpem@5 9801 // Set display variables
philpem@5 9802 width = cimg::min(dimw,(unsigned int)screen_dimx());
philpem@5 9803 height = cimg::min(dimh,(unsigned int)screen_dimy());
philpem@5 9804 normalization = normalization_type<4?normalization_type:3;
philpem@5 9805 is_fullscreen = fullscreen_flag;
philpem@5 9806 is_closed = closed_flag;
philpem@5 9807 lastKeyModifiers = 0;
philpem@5 9808 title = tmp_title;
philpem@5 9809 flush();
philpem@5 9810
philpem@5 9811 // Create the paint CR
philpem@5 9812 if (MPCreateCriticalRegion(&paintCriticalRegion) != noErr)
philpem@5 9813 throw CImgDisplayException("CImgDisplay::_assign() : MPCreateCriticalRegion() failed.");
philpem@5 9814
philpem@5 9815 // Create the thread if it's not already created
philpem@5 9816 if (c.event_thread==0) {
philpem@5 9817 // Background thread does not exists, so create it !
philpem@5 9818 if (pthread_create(&c.event_thread,0,_events_thread,0)!=0)
philpem@5 9819 throw CImgDisplayException("CImgDisplay::_assign() : pthread_create() failed.");
philpem@5 9820 // Wait for thread initialization
philpem@5 9821 MPWaitOnSemaphore(c.sync_event, kDurationForever);
philpem@5 9822 }
philpem@5 9823
philpem@5 9824 // Init disp. graphics
philpem@5 9825 data = new unsigned int[width*height];
philpem@5 9826 _CbInitializeGraphics();
philpem@5 9827
philpem@5 9828 // Now ask the thread to create the window
philpem@5 9829 _CbCreateAttachedWindow(c,ptitle,fullscreen_flag,closed_flag);
philpem@5 9830 return *this;
philpem@5 9831 }
philpem@5 9832
philpem@5 9833 #endif
philpem@5 9834
philpem@5 9835 };
philpem@5 9836
philpem@5 9837 /*
philpem@5 9838 #--------------------------------------
philpem@5 9839 #
philpem@5 9840 #
philpem@5 9841 #
philpem@5 9842 # Definition of the CImg<T> structure
philpem@5 9843 #
philpem@5 9844 #
philpem@5 9845 #
philpem@5 9846 #--------------------------------------
philpem@5 9847 */
philpem@5 9848
philpem@5 9849 //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T.
philpem@5 9850 /**
philpem@5 9851 This is the main class of the %CImg Library. It declares and constructs
philpem@5 9852 an image, allows access to its pixel values, and is able to perform various image operations.
philpem@5 9853
philpem@5 9854 \par Image representation
philpem@5 9855
philpem@5 9856 A %CImg image is defined as an instance of the container \ref CImg<\c T>, which contains a regular grid of pixels,
philpem@5 9857 each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth
philpem@5 9858 and number of channels.
philpem@5 9859 Usually, the three first dimensions are used to describe spatial coordinates <tt>(x,y,z)</tt>, while the number of channels
philpem@5 9860 is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance).
philpem@5 9861 If you need a fifth dimension, you can use image lists \ref CImgList<\c T> rather than simple images \ref CImg<\c T>.
philpem@5 9862
philpem@5 9863 Thus, the \ref CImg<\c T> class is able to represent volumetric images of vector-valued pixels,
philpem@5 9864 as well as images with less dimensions (1D scalar signal, 2D color images, ...).
philpem@5 9865 Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions.
philpem@5 9866
philpem@5 9867 Concerning the pixel value type \c T :
philpem@5 9868 fully supported template types are the basic C++ types : <tt>unsigned char, char, short, unsigned int, int,
philpem@5 9869 unsigned long, long, float, double, ... </tt>.
philpem@5 9870 Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images,
philpem@5 9871 while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt>
philpem@5 9872 images that have floating-point pixel values. The default value for the template T is \c float.
philpem@5 9873 Using your own template types may be possible. However, you will certainly have to define the complete set
philpem@5 9874 of arithmetic and logical operators for your class.
philpem@5 9875
philpem@5 9876 \par Image structure
philpem@5 9877
philpem@5 9878 The \ref CImg<\c T> structure contains \a six fields :
philpem@5 9879 - \ref width defines the number of \a columns of the image (size along the X-axis).
philpem@5 9880 - \ref height defines the number of \a rows of the image (size along the Y-axis).
philpem@5 9881 - \ref depth defines the number of \a slices of the image (size along the Z-axis).
philpem@5 9882 - \ref dim defines the number of \a channels of the image (size along the V-axis).
philpem@5 9883 - \ref data defines a \a pointer to the \a pixel \a data (of type \c T).
philpem@5 9884 - \ref is_shared is a boolean that tells if the memory buffer \ref data is shared with
philpem@5 9885 another image.
philpem@5 9886
philpem@5 9887 You can access these fields publicly although it is recommended to use the dedicated functions
philpem@5 9888 dimx(), dimy(), dimz(), dimv() and ptr() to do so.
philpem@5 9889 Image dimensions are not limited to a specific range (as long as you got enough available memory).
philpem@5 9890 A value of \e 1 usually means that the corresponding dimension is \a flat.
philpem@5 9891 If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty.
philpem@5 9892 Empty images should not contain any pixel data and thus, will not be processed by CImg member functions
philpem@5 9893 (a CImgInstanceException will be thrown instead).
philpem@5 9894 Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage).
philpem@5 9895
philpem@5 9896 \par Image declaration and construction
philpem@5 9897
philpem@5 9898 Declaring an image can be done by using one of the several available constructors.
philpem@5 9899 Here is a list of the most used :
philpem@5 9900
philpem@5 9901 - Construct images from arbitrary dimensions :
philpem@5 9902 - <tt>CImg<char> img;</tt> declares an empty image.
philpem@5 9903 - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with
philpem@5 9904 \c unsigned \c char pixel values.
philpem@5 9905 - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients.
philpem@5 9906 - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image
philpem@5 9907 (colors are stored as an image with three channels).
philpem@5 9908 - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image
philpem@5 9909 (with \c double pixel values).
philpem@5 9910 - <tt>CImg<> img(128,128,128,3);</tt> declares a 128x128x128 volumetric color image
philpem@5 9911 (with \c float pixels, which is the default value of the template parameter \c T).
philpem@5 9912 - \b Note : images pixels are <b>not automatically initialized to 0</b>. You may use the function \ref fill() to
philpem@5 9913 do it, or use the specific constructor taking 5 parameters like this :
philpem@5 9914 <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0.
philpem@5 9915
philpem@5 9916 - Construct images from filenames :
philpem@5 9917 - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg".
philpem@5 9918 - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr".
philpem@5 9919 - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a>
philpem@5 9920 to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io).
philpem@5 9921
philpem@5 9922 - Construct images from C-style arrays :
philpem@5 9923 - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer
philpem@5 9924 \c data_buffer (of size 256x256=65536).
philpem@5 9925 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image
philpem@5 9926 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others).
philpem@5 9927 - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> constructs a 256x256 color image
philpem@5 9928 from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed).
philpem@5 9929
philpem@5 9930 The complete list of constructors can be found <a href="#constructors">here</a>.
philpem@5 9931
philpem@5 9932 \par Most useful functions
philpem@5 9933
philpem@5 9934 The \ref CImg<\c T> class contains a lot of functions that operates on images.
philpem@5 9935 Some of the most useful are :
philpem@5 9936
philpem@5 9937 - operator()(), operator[]() : allows to access or write pixel values.
philpem@5 9938 - display() : displays the image in a new window.
philpem@5 9939 **/
philpem@5 9940 template<typename T>
philpem@5 9941 struct CImg {
philpem@5 9942
philpem@5 9943 //! Variable representing the width of the instance image (i.e. dimensions along the X-axis).
philpem@5 9944 /**
philpem@5 9945 \remark
philpem@5 9946 - Prefer using the function CImg<T>::dimx() to get information about the width of an image.
philpem@5 9947 - Use function CImg<T>::resize() to set a new width for an image. Setting directly the variable \c width would probably
philpem@5 9948 result in a library crash.
philpem@5 9949 - Empty images have \c width defined to \c 0.
philpem@5 9950 **/
philpem@5 9951 unsigned int width;
philpem@5 9952
philpem@5 9953 //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis).
philpem@5 9954 /**
philpem@5 9955 \remark
philpem@5 9956 - Prefer using the function CImg<T>::dimy() to get information about the height of an image.
philpem@5 9957 - Use function CImg<T>::resize() to set a new height for an image. Setting directly the variable \c height would probably
philpem@5 9958 result in a library crash.
philpem@5 9959 - 1D signals have \c height defined to \c 1.
philpem@5 9960 - Empty images have \c height defined to \c 0.
philpem@5 9961 **/
philpem@5 9962 unsigned int height;
philpem@5 9963
philpem@5 9964 //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis).
philpem@5 9965 /**
philpem@5 9966 \remark
philpem@5 9967 - Prefer using the function CImg<T>::dimz() to get information about the depth of an image.
philpem@5 9968 - Use function CImg<T>::resize() to set a new depth for an image. Setting directly the variable \c depth would probably
philpem@5 9969 result in a library crash.
philpem@5 9970 - Classical 2D images have \c depth defined to \c 1.
philpem@5 9971 - Empty images have \c depth defined to \c 0.
philpem@5 9972 **/
philpem@5 9973 unsigned int depth;
philpem@5 9974
philpem@5 9975 //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis).
philpem@5 9976 /**
philpem@5 9977 \remark
philpem@5 9978 - Prefer using the function CImg<T>::dimv() to get information about the depth of an image.
philpem@5 9979 - Use function CImg<T>::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably
philpem@5 9980 result in a library crash.
philpem@5 9981 - Scalar-valued images (one value per pixel) have \c dim defined to \c 1.
philpem@5 9982 - Empty images have \c depth defined to \c 0.
philpem@5 9983 **/
philpem@5 9984 unsigned int dim;
philpem@5 9985
philpem@5 9986 //! Variable telling if pixel buffer of the instance image is shared with another one.
philpem@5 9987 bool is_shared;
philpem@5 9988
philpem@5 9989 //! Pointer to the first pixel of the pixel buffer.
philpem@5 9990 T *data;
philpem@5 9991
philpem@5 9992 //! Iterator type for CImg<T>.
philpem@5 9993 /**
philpem@5 9994 \remark
philpem@5 9995 - An \p iterator is a <tt>T*</tt> pointer (address of a pixel value in the pixel buffer).
philpem@5 9996 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
philpem@5 9997 **/
philpem@5 9998 typedef T* iterator;
philpem@5 9999
philpem@5 10000 //! Const iterator type for CImg<T>.
philpem@5 10001 /**
philpem@5 10002 \remark
philpem@5 10003 - A \p const_iterator is a <tt>const T*</tt> pointer (address of a pixel value in the pixel buffer).
philpem@5 10004 - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL.
philpem@5 10005 **/
philpem@5 10006 typedef const T* const_iterator;
philpem@5 10007
philpem@5 10008 //! Get value type
philpem@5 10009 typedef T value_type;
philpem@5 10010
philpem@5 10011 // Define common T-dependant types.
philpem@5 10012 typedef typename cimg::superset<T,bool>::type Tbool;
philpem@5 10013 typedef typename cimg::superset<T,unsigned char>::type Tuchar;
philpem@5 10014 typedef typename cimg::superset<T,char>::type Tchar;
philpem@5 10015 typedef typename cimg::superset<T,unsigned short>::type Tushort;
philpem@5 10016 typedef typename cimg::superset<T,short>::type Tshort;
philpem@5 10017 typedef typename cimg::superset<T,unsigned int>::type Tuint;
philpem@5 10018 typedef typename cimg::superset<T,int>::type Tint;
philpem@5 10019 typedef typename cimg::superset<T,unsigned long>::type Tulong;
philpem@5 10020 typedef typename cimg::superset<T,long>::type Tlong;
philpem@5 10021 typedef typename cimg::superset<T,float>::type Tfloat;
philpem@5 10022 typedef typename cimg::superset<T,double>::type Tdouble;
philpem@5 10023 typedef typename cimg::last<T,bool>::type boolT;
philpem@5 10024 typedef typename cimg::last<T,unsigned char>::type ucharT;
philpem@5 10025 typedef typename cimg::last<T,char>::type charT;
philpem@5 10026 typedef typename cimg::last<T,unsigned short>::type ushortT;
philpem@5 10027 typedef typename cimg::last<T,short>::type shortT;
philpem@5 10028 typedef typename cimg::last<T,unsigned int>::type uintT;
philpem@5 10029 typedef typename cimg::last<T,int>::type intT;
philpem@5 10030 typedef typename cimg::last<T,unsigned long>::type ulongT;
philpem@5 10031 typedef typename cimg::last<T,long>::type longT;
philpem@5 10032 typedef typename cimg::last<T,float>::type floatT;
philpem@5 10033 typedef typename cimg::last<T,double>::type doubleT;
philpem@5 10034
philpem@5 10035 //@}
philpem@5 10036 //---------------------------
philpem@5 10037 //
philpem@5 10038 //! \name Plugins
philpem@5 10039 //@{
philpem@5 10040 //---------------------------
philpem@5 10041 #ifdef cimg_plugin
philpem@5 10042 #include cimg_plugin
philpem@5 10043 #endif
philpem@5 10044 #ifdef cimg_plugin1
philpem@5 10045 #include cimg_plugin1
philpem@5 10046 #endif
philpem@5 10047 #ifdef cimg_plugin2
philpem@5 10048 #include cimg_plugin2
philpem@5 10049 #endif
philpem@5 10050 #ifdef cimg_plugin3
philpem@5 10051 #include cimg_plugin3
philpem@5 10052 #endif
philpem@5 10053 #ifdef cimg_plugin4
philpem@5 10054 #include cimg_plugin4
philpem@5 10055 #endif
philpem@5 10056 #ifdef cimg_plugin5
philpem@5 10057 #include cimg_plugin5
philpem@5 10058 #endif
philpem@5 10059 #ifdef cimg_plugin6
philpem@5 10060 #include cimg_plugin6
philpem@5 10061 #endif
philpem@5 10062 #ifdef cimg_plugin7
philpem@5 10063 #include cimg_plugin7
philpem@5 10064 #endif
philpem@5 10065 #ifdef cimg_plugin8
philpem@5 10066 #include cimg_plugin8
philpem@5 10067 #endif
philpem@5 10068 #ifndef cimg_plugin_greycstoration
philpem@5 10069 #define cimg_plugin_greycstoration_count
philpem@5 10070 #endif
philpem@5 10071 #ifndef cimg_plugin_greycstoration_lock
philpem@5 10072 #define cimg_plugin_greycstoration_lock
philpem@5 10073 #endif
philpem@5 10074 #ifndef cimg_plugin_greycstoration_unlock
philpem@5 10075 #define cimg_plugin_greycstoration_unlock
philpem@5 10076 #endif
philpem@5 10077
philpem@5 10078 //@}
philpem@5 10079
philpem@5 10080 //--------------------------------------
philpem@5 10081 //
philpem@5 10082 //! \name Constructors-Destructor-Copy
philpem@5 10083 //@{
philpem@5 10084 //--------------------------------------
philpem@5 10085
philpem@5 10086 //! Destructor.
philpem@5 10087 /**
philpem@5 10088 The destructor destroys the instance image.
philpem@5 10089 \remark
philpem@5 10090 - Destructing an empty or shared image does nothing.
philpem@5 10091 - Otherwise, all memory used to store the pixel data of the instance image is freed.
philpem@5 10092 - When destroying a non-shared image, be sure that every shared instances of the same image are
philpem@5 10093 also destroyed to avoid further access to desallocated memory buffers.
philpem@5 10094 **/
philpem@5 10095 ~CImg() {
philpem@5 10096 if (data && !is_shared) delete[] data;
philpem@5 10097 }
philpem@5 10098
philpem@5 10099 //! Default constructor.
philpem@5 10100 /**
philpem@5 10101 The default constructor creates an empty instance image.
philpem@5 10102 \remark
philpem@5 10103 - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim
philpem@5 10104 set to 0 as well as its pointer to the pixel buffer \ref data.
philpem@5 10105 - An empty image is non-shared.
philpem@5 10106 **/
philpem@5 10107 CImg():
philpem@5 10108 width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {}
philpem@5 10109
philpem@5 10110 //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv).
philpem@5 10111 /**
philpem@5 10112 This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
philpem@5 10113 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
philpem@5 10114 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
philpem@5 10115 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
philpem@5 10116 \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim.
philpem@5 10117 \remark
philpem@5 10118 - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty
philpem@5 10119 and all has its dimensions set to 0. No memory for pixel data is then allocated.
philpem@5 10120 - This constructor creates only non-shared images.
philpem@5 10121 - Image pixels allocated by this constructor are \b not \b initialized.
philpem@5 10122 Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
philpem@5 10123 to get an image of desired size with pixels set to a particular value.
philpem@5 10124 **/
philpem@5 10125 explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1):
philpem@5 10126 is_shared(false) {
philpem@5 10127 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10128 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; }
philpem@5 10129 else { width = height = depth = dim = 0; data = 0; }
philpem@5 10130 }
philpem@5 10131
philpem@5 10132 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val.
philpem@5 10133 /**
philpem@5 10134 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T and sets all pixel
philpem@5 10135 values of the created instance image to \p val.
philpem@5 10136 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
philpem@5 10137 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
philpem@5 10138 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
philpem@5 10139 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
philpem@5 10140 \param val Default value for image pixels.
philpem@5 10141 \remark
philpem@5 10142 - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
philpem@5 10143 **/
philpem@5 10144 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val):
philpem@5 10145 is_shared(false) {
philpem@5 10146 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10147 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); }
philpem@5 10148 else { width = height = depth = dim = 0; data = 0; }
philpem@5 10149 }
philpem@5 10150
philpem@5 10151 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (int version).
philpem@5 10152 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
philpem@5 10153 const int val0, const int val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10154 #define _CImg_stdarg(img,a0,a1,N,t) { \
philpem@5 10155 unsigned int _siz = (unsigned int)N; \
philpem@5 10156 if (_siz--) { \
philpem@5 10157 va_list ap; \
philpem@5 10158 va_start(ap,a1); \
philpem@5 10159 T *ptrd = (img).data; \
philpem@5 10160 *(ptrd++) = (T)a0; \
philpem@5 10161 if (_siz--) { \
philpem@5 10162 *(ptrd++) = (T)a1; \
philpem@5 10163 for (; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \
philpem@5 10164 } \
philpem@5 10165 va_end(ap); \
philpem@5 10166 }}
philpem@5 10167 assign(dx,dy,dz,dv);
philpem@5 10168 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
philpem@5 10169 }
philpem@5 10170
philpem@5 10171 //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with specified pixel values (double version).
philpem@5 10172 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
philpem@5 10173 const double val0, const double val1, ...):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10174 assign(dx,dy,dz,dv);
philpem@5 10175 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
philpem@5 10176 }
philpem@5 10177
philpem@5 10178 //! Construct an image with given size and with specified values given in a string.
philpem@5 10179 CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
philpem@5 10180 const char *const values, const bool repeat_pattern):is_shared(false) {
philpem@5 10181 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10182 if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(values,repeat_pattern); }
philpem@5 10183 else { width = height = depth = dim = 0; data = 0; }
philpem@5 10184 }
philpem@5 10185
philpem@5 10186 //! Construct an image from a raw memory buffer.
philpem@5 10187 /**
philpem@5 10188 This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by
philpem@5 10189 copying data values from the input raw pixel buffer \p data_buffer.
philpem@5 10190 **/
philpem@5 10191 template<typename t>
philpem@5 10192 CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
philpem@5 10193 const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) {
philpem@5 10194 if (shared)
philpem@5 10195 throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a (%s*) buffer "
philpem@5 10196 "(different pixel types).",
philpem@5 10197 pixel_type(),CImg<t>::pixel_type());
philpem@5 10198 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10199 if (data_buffer && siz) {
philpem@5 10200 width = dx; height = dy; depth = dz; dim = dv; data = new T[siz];
philpem@5 10201 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
philpem@5 10202 } else { width = height = depth = dim = 0; data = 0; }
philpem@5 10203 }
philpem@5 10204
philpem@5 10205 #ifndef cimg_use_visualcpp6
philpem@5 10206 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
philpem@5 10207 const unsigned int dz=1, const unsigned int dv=1, const bool shared=false)
philpem@5 10208 #else
philpem@5 10209 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
philpem@5 10210 const unsigned int dz, const unsigned int dv, const bool shared)
philpem@5 10211 #endif
philpem@5 10212 {
philpem@5 10213 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10214 if (data_buffer && siz) {
philpem@5 10215 width = dx; height = dy; depth = dz; dim = dv; is_shared = shared;
philpem@5 10216 if (is_shared) data = const_cast<T*>(data_buffer);
philpem@5 10217 else { data = new T[siz]; cimg_std::memcpy(data,data_buffer,siz*sizeof(T)); }
philpem@5 10218 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
philpem@5 10219 }
philpem@5 10220
philpem@5 10221 //! Default copy constructor.
philpem@5 10222 /**
philpem@5 10223 The default copy constructor creates a new instance image having same dimensions
philpem@5 10224 (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img.
philpem@5 10225 \param img The input image to copy.
philpem@5 10226 \remark
philpem@5 10227 - If the input image \p img is non-shared or have a different template type \p t != \p T,
philpem@5 10228 the default copy constructor allocates a new pixel buffer and copy the pixel data
philpem@5 10229 of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different
philpem@5 10230 and the resulting instance image is non-shared.
philpem@5 10231 - If the input image \p img is shared and has the same template type \p t == \p T,
philpem@5 10232 the default copy constructor does not allocate a new pixel buffer and the resulting instance image
philpem@5 10233 shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies
philpem@5 10234 the created instance image.
philpem@5 10235 - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from
philpem@5 10236 type \p t to type \p T.
philpem@5 10237 - Copying an image having the same template type \p t == \p T is significantly faster.
philpem@5 10238 **/
philpem@5 10239 template<typename t>
philpem@5 10240 CImg(const CImg<t>& img):is_shared(false) {
philpem@5 10241 const unsigned int siz = img.size();
philpem@5 10242 if (img.data && siz) {
philpem@5 10243 width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
philpem@5 10244 const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
philpem@5 10245 } else { width = height = depth = dim = 0; data = 0; }
philpem@5 10246 }
philpem@5 10247
philpem@5 10248 CImg(const CImg<T>& img) {
philpem@5 10249 const unsigned int siz = img.size();
philpem@5 10250 if (img.data && siz) {
philpem@5 10251 width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared;
philpem@5 10252 if (is_shared) data = const_cast<T*>(img.data);
philpem@5 10253 else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
philpem@5 10254 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
philpem@5 10255 }
philpem@5 10256
philpem@5 10257 //! Advanced copy constructor.
philpem@5 10258 /**
philpem@5 10259 The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions
philpem@5 10260 \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img.
philpem@5 10261 But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter
philpem@5 10262 \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false).
philpem@5 10263 \param img The input image to copy.
philpem@5 10264 \param shared Boolean flag that decides if the copy is shared on non-shared.
philpem@5 10265 \remark
philpem@5 10266 - It is not possible to create a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
philpem@5 10267 - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data.
philpem@5 10268 - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance
philpem@5 10269 image is the same as the one used by the input image \p img.
philpem@5 10270 **/
philpem@5 10271 template<typename t>
philpem@5 10272 CImg(const CImg<t>& img, const bool shared):is_shared(false) {
philpem@5 10273 if (shared)
philpem@5 10274 throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared instance image from a CImg<%s> instance "
philpem@5 10275 "(different pixel types).",
philpem@5 10276 pixel_type(),CImg<t>::pixel_type());
philpem@5 10277 const unsigned int siz = img.size();
philpem@5 10278 if (img.data && siz) {
philpem@5 10279 width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz];
philpem@5 10280 const t *ptrs = img.data + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
philpem@5 10281 } else { width = height = depth = dim = 0; data = 0; }
philpem@5 10282 }
philpem@5 10283
philpem@5 10284 CImg(const CImg<T>& img, const bool shared) {
philpem@5 10285 const unsigned int siz = img.size();
philpem@5 10286 if (img.data && siz) {
philpem@5 10287 width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared;
philpem@5 10288 if (is_shared) data = const_cast<T*>(img.data);
philpem@5 10289 else { data = new T[siz]; cimg_std::memcpy(data,img.data,siz*sizeof(T)); }
philpem@5 10290 } else { width = height = depth = dim = 0; is_shared = false; data = 0; }
philpem@5 10291 }
philpem@5 10292
philpem@5 10293 //! Construct an image using dimensions of another image
philpem@5 10294 template<typename t>
philpem@5 10295 CImg(const CImg<t>& img, const char *const dimensions):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10296 assign(img,dimensions);
philpem@5 10297 }
philpem@5 10298
philpem@5 10299 //! Construct an image using dimensions of another image, and fill it with a default value
philpem@5 10300 template<typename t>
philpem@5 10301 CImg(const CImg<t>& img, const char *const dimensions, const T val):
philpem@5 10302 width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10303 assign(img,dimensions).fill(val);
philpem@5 10304 }
philpem@5 10305
philpem@5 10306 //! Construct an image from an image file.
philpem@5 10307 /**
philpem@5 10308 This constructor creates an instance image by reading it from a file.
philpem@5 10309 \param filename Filename of the image file.
philpem@5 10310 \remark
philpem@5 10311 - The image format is deduced from the filename only by looking for the filename extension i.e. without
philpem@5 10312 analyzing the file itself.
philpem@5 10313 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
philpem@5 10314 More informations on this topic can be found in cimg_files_io.
philpem@5 10315 - If the filename is not found, a CImgIOException is thrown by this constructor.
philpem@5 10316 **/
philpem@5 10317 CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10318 assign(filename);
philpem@5 10319 }
philpem@5 10320
philpem@5 10321 //! Construct an image from the content of a CImgDisplay instance.
philpem@5 10322 CImg(const CImgDisplay &disp):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {
philpem@5 10323 disp.snapshot(*this);
philpem@5 10324 }
philpem@5 10325
philpem@5 10326 //! In-place version of the default constructor/destructor.
philpem@5 10327 /**
philpem@5 10328 This function replaces the instance image by an empty image.
philpem@5 10329 \remark
philpem@5 10330 - Memory used by the previous content of the instance image is freed if necessary.
philpem@5 10331 - If the instance image was initially shared, it is replaced by a (non-shared) empty image.
philpem@5 10332 - This function is useful to free memory used by an image that is not of use, but which
philpem@5 10333 has been created in the current code scope (i.e. not destroyed yet).
philpem@5 10334 **/
philpem@5 10335 CImg<T>& assign() {
philpem@5 10336 if (data && !is_shared) delete[] data;
philpem@5 10337 width = height = depth = dim = 0; is_shared = false; data = 0;
philpem@5 10338 return *this;
philpem@5 10339 }
philpem@5 10340
philpem@5 10341 //! In-place version of the default constructor.
philpem@5 10342 /**
philpem@5 10343 This function is strictly equivalent to \ref assign() and has been
philpem@5 10344 introduced for having a STL-compliant function name.
philpem@5 10345 **/
philpem@5 10346 CImg<T>& clear() {
philpem@5 10347 return assign();
philpem@5 10348 }
philpem@5 10349
philpem@5 10350 //! In-place version of the previous constructor.
philpem@5 10351 /**
philpem@5 10352 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T.
philpem@5 10353 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
philpem@5 10354 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
philpem@5 10355 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
philpem@5 10356 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
philpem@5 10357 - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty
philpem@5 10358 and all has its dimensions set to 0. No memory for pixel data is then allocated.
philpem@5 10359 - Memory buffer used to store previous pixel values is freed if necessary.
philpem@5 10360 - If the instance image is shared, this constructor actually does nothing more than verifying
philpem@5 10361 that new and old image dimensions fit.
philpem@5 10362 - Image pixels allocated by this function are \b not \b initialized.
philpem@5 10363 Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T)
philpem@5 10364 to assign an image of desired size with pixels set to a particular value.
philpem@5 10365 **/
philpem@5 10366 CImg<T>& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 10367 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10368 if (!siz) return assign();
philpem@5 10369 const unsigned long curr_siz = size();
philpem@5 10370 if (siz!=curr_siz) {
philpem@5 10371 if (is_shared)
philpem@5 10372 throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).",
philpem@5 10373 pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data);
philpem@5 10374 else { if (data) delete[] data; data = new T[siz]; }
philpem@5 10375 }
philpem@5 10376 width = dx; height = dy; depth = dz; dim = dv;
philpem@5 10377 return *this;
philpem@5 10378 }
philpem@5 10379
philpem@5 10380 //! In-place version of the previous constructor.
philpem@5 10381 /**
philpem@5 10382 This function replaces the instance image by a new image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T
philpem@5 10383 and sets all pixel values of the instance image to \p val.
philpem@5 10384 \param dx Desired size along the X-axis, i.e. the \ref width of the image.
philpem@5 10385 \param dy Desired size along the Y-axis, i.e. the \ref height of the image.
philpem@5 10386 \param dz Desired size along the Z-axis, i.e. the \ref depth of the image.
philpem@5 10387 \param dv Desired size along the V-axis, i.e. the number of image channels \p dim.
philpem@5 10388 \param val Default value for image pixels.
philpem@5 10389 \remark
philpem@5 10390 - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int).
philpem@5 10391 **/
philpem@5 10392 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T val) {
philpem@5 10393 return assign(dx,dy,dz,dv).fill(val);
philpem@5 10394 }
philpem@5 10395
philpem@5 10396 //! In-place version of the previous constructor.
philpem@5 10397 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
philpem@5 10398 const int val0, const int val1, ...) {
philpem@5 10399 assign(dx,dy,dz,dv);
philpem@5 10400 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,int);
philpem@5 10401 return *this;
philpem@5 10402 }
philpem@5 10403
philpem@5 10404 //! In-place version of the previous constructor.
philpem@5 10405 CImg<T>& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv,
philpem@5 10406 const double val0, const double val1, ...) {
philpem@5 10407 assign(dx,dy,dz,dv);
philpem@5 10408 _CImg_stdarg(*this,val0,val1,dx*dy*dz*dv,double);
philpem@5 10409 return *this;
philpem@5 10410 }
philpem@5 10411
philpem@5 10412 //! In-place version of the previous constructor.
philpem@5 10413 template<typename t>
philpem@5 10414 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1,
philpem@5 10415 const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 10416 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10417 if (!data_buffer || !siz) return assign();
philpem@5 10418 assign(dx,dy,dz,dv);
philpem@5 10419 const t *ptrs = data_buffer + siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs);
philpem@5 10420 return *this;
philpem@5 10421 }
philpem@5 10422
philpem@5 10423 #ifndef cimg_use_visualcpp6
philpem@5 10424 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1,
philpem@5 10425 const unsigned int dz=1, const unsigned int dv=1)
philpem@5 10426 #else
philpem@5 10427 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
philpem@5 10428 const unsigned int dz, const unsigned int dv)
philpem@5 10429 #endif
philpem@5 10430 {
philpem@5 10431 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10432 if (!data_buffer || !siz) return assign();
philpem@5 10433 const unsigned long curr_siz = size();
philpem@5 10434 if (data_buffer==data && siz==curr_siz) return assign(dx,dy,dz,dv);
philpem@5 10435 if (is_shared || data_buffer+siz<data || data_buffer>=data+size()) {
philpem@5 10436 assign(dx,dy,dz,dv);
philpem@5 10437 if (is_shared) cimg_std::memmove(data,data_buffer,siz*sizeof(T));
philpem@5 10438 else cimg_std::memcpy(data,data_buffer,siz*sizeof(T));
philpem@5 10439 } else {
philpem@5 10440 T *new_data = new T[siz];
philpem@5 10441 cimg_std::memcpy(new_data,data_buffer,siz*sizeof(T));
philpem@5 10442 delete[] data; data = new_data; width = dx; height = dy; depth = dz; dim = dv;
philpem@5 10443 }
philpem@5 10444 return *this;
philpem@5 10445 }
philpem@5 10446
philpem@5 10447 //! In-place version of the previous constructor, allowing to force the shared state of the instance image.
philpem@5 10448 template<typename t>
philpem@5 10449 CImg<T>& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy,
philpem@5 10450 const unsigned int dz, const unsigned int dv, const bool shared) {
philpem@5 10451 if (shared)
philpem@5 10452 throw CImgArgumentException("CImg<%s>::assign() : Cannot assign buffer (%s*) to shared instance image (%u,%u,%u,%u,%p)"
philpem@5 10453 "(different pixel types).",
philpem@5 10454 pixel_type(),CImg<t>::pixel_type(),width,height,depth,dim,data);
philpem@5 10455 return assign(data_buffer,dx,dy,dz,dv);
philpem@5 10456 }
philpem@5 10457
philpem@5 10458 CImg<T>& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy,
philpem@5 10459 const unsigned int dz, const unsigned int dv, const bool shared) {
philpem@5 10460 const unsigned long siz = dx*dy*dz*dv;
philpem@5 10461 if (!data_buffer || !siz) return assign();
philpem@5 10462 if (!shared) { if (is_shared) assign(); assign(data_buffer,dx,dy,dz,dv); }
philpem@5 10463 else {
philpem@5 10464 if (!is_shared) {
philpem@5 10465 if (data_buffer+siz<data || data_buffer>=data+size()) assign();
philpem@5 10466 else cimg::warn("CImg<%s>::assign() : Shared instance image has overlapping memory !",
philpem@5 10467 pixel_type());
philpem@5 10468 }
philpem@5 10469 width = dx; height = dy; depth = dz; dim = dv; is_shared = true;
philpem@5 10470 data = const_cast<T*>(data_buffer);
philpem@5 10471 }
philpem@5 10472 return *this;
philpem@5 10473 }
philpem@5 10474
philpem@5 10475 //! In-place version of the default copy constructor.
philpem@5 10476 /**
philpem@5 10477 This function assigns a copy of the input image \p img to the current instance image.
philpem@5 10478 \param img The input image to copy.
philpem@5 10479 \remark
philpem@5 10480 - If the instance image is not shared, the content of the input image \p img is copied into a new buffer
philpem@5 10481 becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary.
philpem@5 10482 - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer
philpem@5 10483 of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared.
philpem@5 10484 **/
philpem@5 10485 template<typename t>
philpem@5 10486 CImg<T>& assign(const CImg<t>& img) {
philpem@5 10487 return assign(img.data,img.width,img.height,img.depth,img.dim);
philpem@5 10488 }
philpem@5 10489
philpem@5 10490 //! In-place version of the advanced constructor.
philpem@5 10491 /**
philpem@5 10492 This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the
philpem@5 10493 current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \c true)
philpem@5 10494 or non-shared (if the input parameter \p shared is set to \c false).
philpem@5 10495 \param img The input image to copy.
philpem@5 10496 \param shared Boolean flag that decides if the copy is shared or non-shared.
philpem@5 10497 \remark
philpem@5 10498 - It is not possible to assign a shared copy if the input image \p img is empty or has a different pixel type \p t != \p T.
philpem@5 10499 - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data.
philpem@5 10500 - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance
philpem@5 10501 image is the same as the one used by the input image \p img.
philpem@5 10502 **/
philpem@5 10503 template<typename t>
philpem@5 10504 CImg<T>& assign(const CImg<t>& img, const bool shared) {
philpem@5 10505 return assign(img.data,img.width,img.height,img.depth,img.dim,shared);
philpem@5 10506 }
philpem@5 10507
philpem@5 10508 //! In-place version of the previous constructor.
philpem@5 10509 template<typename t>
philpem@5 10510 CImg<T>& assign(const CImg<t>& img, const char *const dimensions) {
philpem@5 10511 if (dimensions) {
philpem@5 10512 unsigned int siz[4] = { 0,1,1,1 };
philpem@5 10513 const char *s = dimensions;
philpem@5 10514 char tmp[256] = { 0 }, c = 0;
philpem@5 10515 int val = 0;
philpem@5 10516 for (unsigned int k=0; k<4; ++k) {
philpem@5 10517 const int err = cimg_std::sscanf(s,"%[-0-9]%c",tmp,&c);
philpem@5 10518 if (err>=1) {
philpem@5 10519 const int err = cimg_std::sscanf(s,"%d",&val);
philpem@5 10520 if (err==1) {
philpem@5 10521 int val2 = val<0?-val:(c=='%'?val:-1);
philpem@5 10522 if (val2>=0) {
philpem@5 10523 val = (int)((k==0?img.width:(k==1?img.height:(k==2?img.depth:img.dim)))*val2/100);
philpem@5 10524 if (c!='%' && !val) val = 1;
philpem@5 10525 }
philpem@5 10526 siz[k] = val;
philpem@5 10527 }
philpem@5 10528 s+=cimg::strlen(tmp);
philpem@5 10529 if (c=='%') ++s;
philpem@5 10530 }
philpem@5 10531 if (!err) {
philpem@5 10532 if (!cimg::strncasecmp(s,"x",1)) { ++s; siz[k] = img.width; }
philpem@5 10533 else if (!cimg::strncasecmp(s,"y",1)) { ++s; siz[k] = img.height; }
philpem@5 10534 else if (!cimg::strncasecmp(s,"z",1)) { ++s; siz[k] = img.depth; }
philpem@5 10535 else if (!cimg::strncasecmp(s,"v",1)) { ++s; siz[k] = img.dim; }
philpem@5 10536 else if (!cimg::strncasecmp(s,"dx",2)) { s+=2; siz[k] = img.width; }
philpem@5 10537 else if (!cimg::strncasecmp(s,"dy",2)) { s+=2; siz[k] = img.height; }
philpem@5 10538 else if (!cimg::strncasecmp(s,"dz",2)) { s+=2; siz[k] = img.depth; }
philpem@5 10539 else if (!cimg::strncasecmp(s,"dv",2)) { s+=2; siz[k] = img.dim; }
philpem@5 10540 else if (!cimg::strncasecmp(s,"dimx",4)) { s+=4; siz[k] = img.width; }
philpem@5 10541 else if (!cimg::strncasecmp(s,"dimy",4)) { s+=4; siz[k] = img.height; }
philpem@5 10542 else if (!cimg::strncasecmp(s,"dimz",4)) { s+=4; siz[k] = img.depth; }
philpem@5 10543 else if (!cimg::strncasecmp(s,"dimv",4)) { s+=4; siz[k] = img.dim; }
philpem@5 10544 else if (!cimg::strncasecmp(s,"width",5)) { s+=5; siz[k] = img.width; }
philpem@5 10545 else if (!cimg::strncasecmp(s,"height",6)) { s+=6; siz[k] = img.height; }
philpem@5 10546 else if (!cimg::strncasecmp(s,"depth",5)) { s+=5; siz[k] = img.depth; }
philpem@5 10547 else if (!cimg::strncasecmp(s,"dim",3)) { s+=3; siz[k] = img.dim; }
philpem@5 10548 else { ++s; --k; }
philpem@5 10549 }
philpem@5 10550 }
philpem@5 10551 return assign(siz[0],siz[1],siz[2],siz[3]);
philpem@5 10552 }
philpem@5 10553 return assign();
philpem@5 10554 }
philpem@5 10555
philpem@5 10556 //! In-place version of the previous constructor.
philpem@5 10557 template<typename t>
philpem@5 10558 CImg<T>& assign(const CImg<t>& img, const char *const dimensions, const T val) {
philpem@5 10559 return assign(img,dimensions).fill(val);
philpem@5 10560 }
philpem@5 10561
philpem@5 10562 //! In-place version of the previous constructor.
philpem@5 10563 /**
philpem@5 10564 This function replaces the instance image by the one that have been read from the given file.
philpem@5 10565 \param filename Filename of the image file.
philpem@5 10566 - The image format is deduced from the filename only by looking for the filename extension i.e. without
philpem@5 10567 analyzing the file itself.
philpem@5 10568 - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with.
philpem@5 10569 More informations on this topic can be found in cimg_files_io.
philpem@5 10570 - If the filename is not found, a CImgIOException is thrown by this constructor.
philpem@5 10571 **/
philpem@5 10572 CImg<T>& assign(const char *const filename) {
philpem@5 10573 return load(filename);
philpem@5 10574 }
philpem@5 10575
philpem@5 10576 //! In-place version of the previous constructor.
philpem@5 10577 CImg<T>& assign(const CImgDisplay &disp) {
philpem@5 10578 disp.snapshot(*this);
philpem@5 10579 return *this;
philpem@5 10580 }
philpem@5 10581
philpem@5 10582 //! Transfer the content of the instance image into another one in a way that memory copies are avoided if possible.
philpem@5 10583 /**
philpem@5 10584 The instance image is always empty after a call to this function.
philpem@5 10585 **/
philpem@5 10586 template<typename t>
philpem@5 10587 CImg<t>& transfer_to(CImg<t>& img) {
philpem@5 10588 img.assign(*this);
philpem@5 10589 assign();
philpem@5 10590 return img;
philpem@5 10591 }
philpem@5 10592
philpem@5 10593 CImg<T>& transfer_to(CImg<T>& img) {
philpem@5 10594 if (is_shared || img.is_shared) { img.assign(*this); assign(); } else { img.assign(); swap(img); }
philpem@5 10595 return img;
philpem@5 10596 }
philpem@5 10597
philpem@5 10598 //! Swap all fields of two images. Use with care !
philpem@5 10599 CImg<T>& swap(CImg<T>& img) {
philpem@5 10600 cimg::swap(width,img.width);
philpem@5 10601 cimg::swap(height,img.height);
philpem@5 10602 cimg::swap(depth,img.depth);
philpem@5 10603 cimg::swap(dim,img.dim);
philpem@5 10604 cimg::swap(data,img.data);
philpem@5 10605 cimg::swap(is_shared,img.is_shared);
philpem@5 10606 return img;
philpem@5 10607 }
philpem@5 10608
philpem@5 10609 //@}
philpem@5 10610 //-------------------------------------
philpem@5 10611 //
philpem@5 10612 //! \name Image Informations
philpem@5 10613 //@{
philpem@5 10614 //-------------------------------------
philpem@5 10615
philpem@5 10616 //! Return the type of the pixel values.
philpem@5 10617 /**
philpem@5 10618 \return a string describing the type of the image pixels (template parameter \p T).
philpem@5 10619 - The string returned may contains spaces (<tt>"unsigned char"</tt>).
philpem@5 10620 - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned.
philpem@5 10621 **/
philpem@5 10622 static const char* pixel_type() {
philpem@5 10623 return cimg::type<T>::string();
philpem@5 10624 }
philpem@5 10625
philpem@5 10626 //! Return the total number of pixel values in an image.
philpem@5 10627 /**
philpem@5 10628 - Equivalent to : dimx() * dimy() * dimz() * dimv().
philpem@5 10629
philpem@5 10630 \par example:
philpem@5 10631 \code
philpem@5 10632 CImg<> img(100,100,1,3);
philpem@5 10633 if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true");
philpem@5 10634 \endcode
philpem@5 10635 **/
philpem@5 10636 unsigned long size() const {
philpem@5 10637 return width*height*depth*dim;
philpem@5 10638 }
philpem@5 10639
philpem@5 10640 //! Return the number of columns of the instance image (size along the X-axis, i.e image width).
philpem@5 10641 int dimx() const {
philpem@5 10642 return (int)width;
philpem@5 10643 }
philpem@5 10644
philpem@5 10645 //! Return the number of rows of the instance image (size along the Y-axis, i.e image height).
philpem@5 10646 int dimy() const {
philpem@5 10647 return (int)height;
philpem@5 10648 }
philpem@5 10649
philpem@5 10650 //! Return the number of slices of the instance image (size along the Z-axis).
philpem@5 10651 int dimz() const {
philpem@5 10652 return (int)depth;
philpem@5 10653 }
philpem@5 10654
philpem@5 10655 //! Return the number of vector channels of the instance image (size along the V-axis).
philpem@5 10656 int dimv() const {
philpem@5 10657 return (int)dim;
philpem@5 10658 }
philpem@5 10659
philpem@5 10660 //! Return \c true if image (*this) has the specified width.
philpem@5 10661 bool is_sameX(const unsigned int dx) const {
philpem@5 10662 return (width==dx);
philpem@5 10663 }
philpem@5 10664
philpem@5 10665 //! Return \c true if images \c (*this) and \c img have same width.
philpem@5 10666 template<typename t>
philpem@5 10667 bool is_sameX(const CImg<t>& img) const {
philpem@5 10668 return is_sameX(img.width);
philpem@5 10669 }
philpem@5 10670
philpem@5 10671 //! Return \c true if images \c (*this) and the display \c disp have same width.
philpem@5 10672 bool is_sameX(const CImgDisplay& disp) const {
philpem@5 10673 return is_sameX(disp.width);
philpem@5 10674 }
philpem@5 10675
philpem@5 10676 //! Return \c true if image (*this) has the specified height.
philpem@5 10677 bool is_sameY(const unsigned int dy) const {
philpem@5 10678 return (height==dy);
philpem@5 10679 }
philpem@5 10680
philpem@5 10681 //! Return \c true if images \c (*this) and \c img have same height.
philpem@5 10682 template<typename t>
philpem@5 10683 bool is_sameY(const CImg<t>& img) const {
philpem@5 10684 return is_sameY(img.height);
philpem@5 10685 }
philpem@5 10686
philpem@5 10687 //! Return \c true if images \c (*this) and the display \c disp have same height.
philpem@5 10688 bool is_sameY(const CImgDisplay& disp) const {
philpem@5 10689 return is_sameY(disp.height);
philpem@5 10690 }
philpem@5 10691
philpem@5 10692 //! Return \c true if image (*this) has the specified depth.
philpem@5 10693 bool is_sameZ(const unsigned int dz) const {
philpem@5 10694 return (depth==dz);
philpem@5 10695 }
philpem@5 10696
philpem@5 10697 //! Return \c true if images \c (*this) and \c img have same depth.
philpem@5 10698 template<typename t>
philpem@5 10699 bool is_sameZ(const CImg<t>& img) const {
philpem@5 10700 return is_sameZ(img.depth);
philpem@5 10701 }
philpem@5 10702
philpem@5 10703 //! Return \c true if image (*this) has the specified number of channels.
philpem@5 10704 bool is_sameV(const unsigned int dv) const {
philpem@5 10705 return (dim==dv);
philpem@5 10706 }
philpem@5 10707
philpem@5 10708 //! Return \c true if images \c (*this) and \c img have same dim.
philpem@5 10709 template<typename t>
philpem@5 10710 bool is_sameV(const CImg<t>& img) const {
philpem@5 10711 return is_sameV(img.dim);
philpem@5 10712 }
philpem@5 10713
philpem@5 10714 //! Return \c true if image (*this) has the specified width and height.
philpem@5 10715 bool is_sameXY(const unsigned int dx, const unsigned int dy) const {
philpem@5 10716 return (is_sameX(dx) && is_sameY(dy));
philpem@5 10717 }
philpem@5 10718
philpem@5 10719 //! Return \c true if images have same width and same height.
philpem@5 10720 template<typename t>
philpem@5 10721 bool is_sameXY(const CImg<t>& img) const {
philpem@5 10722 return (is_sameX(img) && is_sameY(img));
philpem@5 10723 }
philpem@5 10724
philpem@5 10725 //! Return \c true if image \c (*this) and the display \c disp have same width and same height.
philpem@5 10726 bool is_sameXY(const CImgDisplay& disp) const {
philpem@5 10727 return (is_sameX(disp) && is_sameY(disp));
philpem@5 10728 }
philpem@5 10729
philpem@5 10730 //! Return \c true if image (*this) has the specified width and depth.
philpem@5 10731 bool is_sameXZ(const unsigned int dx, const unsigned int dz) const {
philpem@5 10732 return (is_sameX(dx) && is_sameZ(dz));
philpem@5 10733 }
philpem@5 10734
philpem@5 10735 //! Return \c true if images have same width and same depth.
philpem@5 10736 template<typename t>
philpem@5 10737 bool is_sameXZ(const CImg<t>& img) const {
philpem@5 10738 return (is_sameX(img) && is_sameZ(img));
philpem@5 10739 }
philpem@5 10740
philpem@5 10741 //! Return \c true if image (*this) has the specified width and number of channels.
philpem@5 10742 bool is_sameXV(const unsigned int dx, const unsigned int dv) const {
philpem@5 10743 return (is_sameX(dx) && is_sameV(dv));
philpem@5 10744 }
philpem@5 10745
philpem@5 10746 //! Return \c true if images have same width and same number of channels.
philpem@5 10747 template<typename t>
philpem@5 10748 bool is_sameXV(const CImg<t>& img) const {
philpem@5 10749 return (is_sameX(img) && is_sameV(img));
philpem@5 10750 }
philpem@5 10751
philpem@5 10752 //! Return \c true if image (*this) has the specified height and depth.
philpem@5 10753 bool is_sameYZ(const unsigned int dy, const unsigned int dz) const {
philpem@5 10754 return (is_sameY(dy) && is_sameZ(dz));
philpem@5 10755 }
philpem@5 10756
philpem@5 10757 //! Return \c true if images have same height and same depth.
philpem@5 10758 template<typename t>
philpem@5 10759 bool is_sameYZ(const CImg<t>& img) const {
philpem@5 10760 return (is_sameY(img) && is_sameZ(img));
philpem@5 10761 }
philpem@5 10762
philpem@5 10763 //! Return \c true if image (*this) has the specified height and number of channels.
philpem@5 10764 bool is_sameYV(const unsigned int dy, const unsigned int dv) const {
philpem@5 10765 return (is_sameY(dy) && is_sameV(dv));
philpem@5 10766 }
philpem@5 10767
philpem@5 10768 //! Return \c true if images have same height and same number of channels.
philpem@5 10769 template<typename t>
philpem@5 10770 bool is_sameYV(const CImg<t>& img) const {
philpem@5 10771 return (is_sameY(img) && is_sameV(img));
philpem@5 10772 }
philpem@5 10773
philpem@5 10774 //! Return \c true if image (*this) has the specified depth and number of channels.
philpem@5 10775 bool is_sameZV(const unsigned int dz, const unsigned int dv) const {
philpem@5 10776 return (is_sameZ(dz) && is_sameV(dv));
philpem@5 10777 }
philpem@5 10778
philpem@5 10779 //! Return \c true if images have same depth and same number of channels.
philpem@5 10780 template<typename t>
philpem@5 10781 bool is_sameZV(const CImg<t>& img) const {
philpem@5 10782 return (is_sameZ(img) && is_sameV(img));
philpem@5 10783 }
philpem@5 10784
philpem@5 10785 //! Return \c true if image (*this) has the specified width, height and depth.
philpem@5 10786 bool is_sameXYZ(const unsigned int dx, const unsigned int dy, const unsigned int dz) const {
philpem@5 10787 return (is_sameXY(dx,dy) && is_sameZ(dz));
philpem@5 10788 }
philpem@5 10789
philpem@5 10790 //! Return \c true if images have same width, same height and same depth.
philpem@5 10791 template<typename t>
philpem@5 10792 bool is_sameXYZ(const CImg<t>& img) const {
philpem@5 10793 return (is_sameXY(img) && is_sameZ(img));
philpem@5 10794 }
philpem@5 10795
philpem@5 10796 //! Return \c true if image (*this) has the specified width, height and depth.
philpem@5 10797 bool is_sameXYV(const unsigned int dx, const unsigned int dy, const unsigned int dv) const {
philpem@5 10798 return (is_sameXY(dx,dy) && is_sameV(dv));
philpem@5 10799 }
philpem@5 10800
philpem@5 10801 //! Return \c true if images have same width, same height and same number of channels.
philpem@5 10802 template<typename t>
philpem@5 10803 bool is_sameXYV(const CImg<t>& img) const {
philpem@5 10804 return (is_sameXY(img) && is_sameV(img));
philpem@5 10805 }
philpem@5 10806
philpem@5 10807 //! Return \c true if image (*this) has the specified width, height and number of channels.
philpem@5 10808 bool is_sameXZV(const unsigned int dx, const unsigned int dz, const unsigned int dv) const {
philpem@5 10809 return (is_sameXZ(dx,dz) && is_sameV(dv));
philpem@5 10810 }
philpem@5 10811
philpem@5 10812 //! Return \c true if images have same width, same depth and same number of channels.
philpem@5 10813 template<typename t>
philpem@5 10814 bool is_sameXZV(const CImg<t>& img) const {
philpem@5 10815 return (is_sameXZ(img) && is_sameV(img));
philpem@5 10816 }
philpem@5 10817
philpem@5 10818 //! Return \c true if image (*this) has the specified height, depth and number of channels.
philpem@5 10819 bool is_sameYZV(const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
philpem@5 10820 return (is_sameYZ(dy,dz) && is_sameV(dv));
philpem@5 10821 }
philpem@5 10822
philpem@5 10823 //! Return \c true if images have same heigth, same depth and same number of channels.
philpem@5 10824 template<typename t>
philpem@5 10825 bool is_sameYZV(const CImg<t>& img) const {
philpem@5 10826 return (is_sameYZ(img) && is_sameV(img));
philpem@5 10827 }
philpem@5 10828
philpem@5 10829 //! Return \c true if image (*this) has the specified width, height, depth and number of channels.
philpem@5 10830 bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
philpem@5 10831 return (is_sameXYZ(dx,dy,dz) && is_sameV(dv));
philpem@5 10832 }
philpem@5 10833
philpem@5 10834 //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels.
philpem@5 10835 template<typename t>
philpem@5 10836 bool is_sameXYZV(const CImg<t>& img) const {
philpem@5 10837 return (is_sameXYZ(img) && is_sameV(img));
philpem@5 10838 }
philpem@5 10839
philpem@5 10840 //! Return \c true if current image is empty.
philpem@5 10841 bool is_empty() const {
philpem@5 10842 return !(data && width && height && depth && dim);
philpem@5 10843 }
philpem@5 10844
philpem@5 10845 //! Return \p true if image is not empty.
philpem@5 10846 operator bool() const {
philpem@5 10847 return !is_empty();
philpem@5 10848 }
philpem@5 10849
philpem@5 10850 //! Return an iterator to the first image pixel
philpem@5 10851 iterator begin() {
philpem@5 10852 return data;
philpem@5 10853 }
philpem@5 10854
philpem@5 10855 const_iterator begin() const {
philpem@5 10856 return data;
philpem@5 10857 }
philpem@5 10858
philpem@5 10859 //! Return reference to the first image pixel
philpem@5 10860 const T& first() const {
philpem@5 10861 return *data;
philpem@5 10862 }
philpem@5 10863
philpem@5 10864 T& first() {
philpem@5 10865 return *data;
philpem@5 10866 }
philpem@5 10867
philpem@5 10868 //! Return an iterator pointing after the last image pixel
philpem@5 10869 iterator end() {
philpem@5 10870 return data + size();
philpem@5 10871 }
philpem@5 10872
philpem@5 10873 const_iterator end() const {
philpem@5 10874 return data + size();
philpem@5 10875 }
philpem@5 10876
philpem@5 10877 //! Return a reference to the last image pixel
philpem@5 10878 const T& last() const {
philpem@5 10879 return data[size() - 1];
philpem@5 10880 }
philpem@5 10881
philpem@5 10882 T& last() {
philpem@5 10883 return data[size() - 1];
philpem@5 10884 }
philpem@5 10885
philpem@5 10886 //! Return a pointer to the pixel buffer.
philpem@5 10887 T* ptr() {
philpem@5 10888 return data;
philpem@5 10889 }
philpem@5 10890
philpem@5 10891 const T* ptr() const {
philpem@5 10892 return data;
philpem@5 10893 }
philpem@5 10894
philpem@5 10895 //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v).
philpem@5 10896 /**
philpem@5 10897 \param x X-coordinate of the pixel.
philpem@5 10898 \param y Y-coordinate of the pixel.
philpem@5 10899 \param z Z-coordinate of the pixel.
philpem@5 10900 \param v V-coordinate of the pixel.
philpem@5 10901
philpem@5 10902 - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer.
philpem@5 10903 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear if
philpem@5 10904 given coordinates are outside the image range (but function performances decrease).
philpem@5 10905
philpem@5 10906 \par example:
philpem@5 10907 \code
philpem@5 10908 CImg<float> img(100,100,1,1,0); // Define a 100x100 greyscale image with float-valued pixels.
philpem@5 10909 float *ptr = ptr(10,10); // Get a pointer to the pixel located at (10,10).
philpem@5 10910 float val = *ptr; // Get the pixel value.
philpem@5 10911 \endcode
philpem@5 10912 **/
philpem@5 10913 #if cimg_debug>=3
philpem@5 10914 T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
philpem@5 10915 const long off = offset(x,y,z,v);
philpem@5 10916 if (off<0 || off>=(long)size()) {
philpem@5 10917 cimg::warn("CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%ld), "
philpem@5 10918 "outside image range (%u,%u,%u,%u) (size=%lu)",
philpem@5 10919 pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
philpem@5 10920 return data;
philpem@5 10921 }
philpem@5 10922 return data + off;
philpem@5 10923 }
philpem@5 10924
philpem@5 10925 const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
philpem@5 10926 return const_cast<CImg<T>*>(this)->ptr(x,y,z,v);
philpem@5 10927 }
philpem@5 10928 #else
philpem@5 10929 T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
philpem@5 10930 return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
philpem@5 10931 }
philpem@5 10932
philpem@5 10933 const T* ptr(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
philpem@5 10934 return data + (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
philpem@5 10935 }
philpem@5 10936 #endif
philpem@5 10937
philpem@5 10938 //! Return \c true if the memory buffers of the two images overlaps.
philpem@5 10939 /**
philpem@5 10940 May happen when using shared images.
philpem@5 10941 **/
philpem@5 10942 template<typename t>
philpem@5 10943 bool is_overlapped(const CImg<t>& img) const {
philpem@5 10944 const unsigned long csiz = size(), isiz = img.size();
philpem@5 10945 return !((void*)(data+csiz)<=(void*)img.data || (void*)data>=(void*)(img.data+isiz));
philpem@5 10946 }
philpem@5 10947
philpem@5 10948 //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data.
philpem@5 10949 /**
philpem@5 10950 \param x X-coordinate of the pixel.
philpem@5 10951 \param y Y-coordinate of the pixel.
philpem@5 10952 \param z Z-coordinate of the pixel.
philpem@5 10953 \param v V-coordinate of the pixel.
philpem@5 10954
philpem@5 10955 - No checking is done on the validity of the given coordinates.
philpem@5 10956
philpem@5 10957 \par Example:
philpem@5 10958 \code
philpem@5 10959 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels.
philpem@5 10960 long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10).
philpem@5 10961 float val = img[off]; // Get the blue value of the pixel.
philpem@5 10962 \endcode
philpem@5 10963 **/
philpem@5 10964 long offset(const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 10965 return (long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth;
philpem@5 10966 }
philpem@5 10967
philpem@5 10968 //! Fast access to pixel value for reading or writing.
philpem@5 10969 /**
philpem@5 10970 \param x X-coordinate of the pixel.
philpem@5 10971 \param y Y-coordinate of the pixel.
philpem@5 10972 \param z Z-coordinate of the pixel.
philpem@5 10973 \param v V-coordinate of the pixel.
philpem@5 10974
philpem@5 10975 - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below).
philpem@5 10976 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
philpem@5 10977 (but function performances decrease).
philpem@5 10978
philpem@5 10979 \par example:
philpem@5 10980 \code
philpem@5 10981 CImg<float> img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels.
philpem@5 10982 const float valR = img(10,10,0,0); // Read the red component at coordinates (10,10).
philpem@5 10983 const float valG = img(10,10,0,1); // Read the green component at coordinates (10,10)
philpem@5 10984 const float valB = img(10,10,2); // Read the blue component at coordinates (10,10) (Z-coordinate omitted here).
philpem@5 10985 const float avg = (valR + valG + valB)/3; // Compute average pixel value.
philpem@5 10986 img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the pixel (10,10) by the average grey value.
philpem@5 10987 \endcode
philpem@5 10988 **/
philpem@5 10989 #if cimg_debug>=3
philpem@5 10990 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
philpem@5 10991 const long off = offset(x,y,z,v);
philpem@5 10992 if (!data || off>=(long)size()) {
philpem@5 10993 cimg::warn("CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%ld) "
philpem@5 10994 "outside the image range (%u,%u,%u,%u) (size=%lu)",
philpem@5 10995 pixel_type(),x,y,z,v,off,width,height,depth,dim,size());
philpem@5 10996 return *data;
philpem@5 10997 }
philpem@5 10998 else return data[off];
philpem@5 10999 }
philpem@5 11000
philpem@5 11001 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
philpem@5 11002 return const_cast<CImg<T>*>(this)->operator()(x,y,z,v);
philpem@5 11003 }
philpem@5 11004 #else
philpem@5 11005 T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) {
philpem@5 11006 return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
philpem@5 11007 }
philpem@5 11008
philpem@5 11009 const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const {
philpem@5 11010 return data[(long)x + (long)y*width + (long)z*width*height + (long)v*width*height*depth];
philpem@5 11011 }
philpem@5 11012 #endif
philpem@5 11013
philpem@5 11014 //! Fast access to pixel value for reading or writing, using an offset to the image pixel.
philpem@5 11015 /**
philpem@5 11016 \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr().
philpem@5 11017
philpem@5 11018 - If the macro \c 'cimg_debug'>=3, boundary checking is performed and warning messages may appear
philpem@5 11019 (but function performances decrease).
philpem@5 11020 - As pixel values are aligned in memory, this operator can sometime useful to access values easier than
philpem@5 11021 with operator()() (see example below).
philpem@5 11022
philpem@5 11023 \par example:
philpem@5 11024 \code
philpem@5 11025 CImg<float> vec(1,10); // Define a vector of float values (10 lines, 1 row).
philpem@5 11026 const float val1 = vec(0,4); // Get the fifth element using operator()().
philpem@5 11027 const float val2 = vec[4]; // Get the fifth element using operator[]. Here, val2==val1.
philpem@5 11028 \endcode
philpem@5 11029 **/
philpem@5 11030 #if cimg_debug>=3
philpem@5 11031 T& operator[](const unsigned long off) {
philpem@5 11032 if (!data || off>=size()) {
philpem@5 11033 cimg::warn("CImg<%s>::operator[] : Pixel access requested at offset=%lu "
philpem@5 11034 "outside the image range (%u,%u,%u,%u) (size=%lu)",
philpem@5 11035 pixel_type(),off,width,height,depth,dim,size());
philpem@5 11036 return *data;
philpem@5 11037 }
philpem@5 11038 else return data[off];
philpem@5 11039 }
philpem@5 11040
philpem@5 11041 const T& operator[](const unsigned long off) const {
philpem@5 11042 return const_cast<CImg<T>*>(this)->operator[](off);
philpem@5 11043 }
philpem@5 11044 #else
philpem@5 11045 T& operator[](const unsigned long off) {
philpem@5 11046 return data[off];
philpem@5 11047 }
philpem@5 11048
philpem@5 11049 const T& operator[](const unsigned long off) const {
philpem@5 11050 return data[off];
philpem@5 11051 }
philpem@5 11052 #endif
philpem@5 11053
philpem@5 11054 //! Return a reference to the last image value
philpem@5 11055 T& back() {
philpem@5 11056 return operator()(size()-1);
philpem@5 11057 }
philpem@5 11058
philpem@5 11059 const T& back() const {
philpem@5 11060 return operator()(size()-1);
philpem@5 11061 }
philpem@5 11062
philpem@5 11063 //! Return a reference to the first image value
philpem@5 11064 T& front() {
philpem@5 11065 return *data;
philpem@5 11066 }
philpem@5 11067
philpem@5 11068 const T& front() const {
philpem@5 11069 return *data;
philpem@5 11070 }
philpem@5 11071
philpem@5 11072 //! Return \c true if pixel (x,y,z,v) is inside image boundaries.
philpem@5 11073 bool containsXYZV(const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 11074 return !is_empty() && x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz() && v>=0 && v<dimv();
philpem@5 11075 }
philpem@5 11076
philpem@5 11077 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z,v).
philpem@5 11078 template<typename t>
philpem@5 11079 bool contains(const T& pixel, t& x, t& y, t& z, t& v) const {
philpem@5 11080 const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
philpem@5 11081 const T *const ppixel = &pixel;
philpem@5 11082 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
philpem@5 11083 unsigned long off = (unsigned long)(ppixel - data);
philpem@5 11084 const unsigned long nv = off/whz;
philpem@5 11085 off%=whz;
philpem@5 11086 const unsigned long nz = off/wh;
philpem@5 11087 off%=wh;
philpem@5 11088 const unsigned long ny = off/width, nx = off%width;
philpem@5 11089 x = (t)nx; y = (t)ny; z = (t)nz; v = (t)nv;
philpem@5 11090 return true;
philpem@5 11091 }
philpem@5 11092
philpem@5 11093 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y,z).
philpem@5 11094 template<typename t>
philpem@5 11095 bool contains(const T& pixel, t& x, t& y, t& z) const {
philpem@5 11096 const unsigned long wh = width*height, whz = wh*depth, siz = whz*dim;
philpem@5 11097 const T *const ppixel = &pixel;
philpem@5 11098 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
philpem@5 11099 unsigned long off = ((unsigned long)(ppixel - data))%whz;
philpem@5 11100 const unsigned long nz = off/wh;
philpem@5 11101 off%=wh;
philpem@5 11102 const unsigned long ny = off/width, nx = off%width;
philpem@5 11103 x = (t)nx; y = (t)ny; z = (t)nz;
philpem@5 11104 return true;
philpem@5 11105 }
philpem@5 11106
philpem@5 11107 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x,y).
philpem@5 11108 template<typename t>
philpem@5 11109 bool contains(const T& pixel, t& x, t& y) const {
philpem@5 11110 const unsigned long wh = width*height, siz = wh*depth*dim;
philpem@5 11111 const T *const ppixel = &pixel;
philpem@5 11112 if (is_empty() || ppixel<data || ppixel>=data+siz) return false;
philpem@5 11113 unsigned long off = ((unsigned long)(ppixel - data))%wh;
philpem@5 11114 const unsigned long ny = off/width, nx = off%width;
philpem@5 11115 x = (t)nx; y = (t)ny;
philpem@5 11116 return true;
philpem@5 11117 }
philpem@5 11118
philpem@5 11119 //! Return \c true if specified referenced value is inside image boundaries. If true, returns pixel coordinates in (x).
philpem@5 11120 template<typename t>
philpem@5 11121 bool contains(const T& pixel, t& x) const {
philpem@5 11122 const T *const ppixel = &pixel;
philpem@5 11123 if (is_empty() || ppixel<data || ppixel>=data+size()) return false;
philpem@5 11124 x = (t)(((unsigned long)(ppixel - data))%width);
philpem@5 11125 return true;
philpem@5 11126 }
philpem@5 11127
philpem@5 11128 //! Return \c true if specified referenced value is inside the image boundaries.
philpem@5 11129 bool contains(const T& pixel) const {
philpem@5 11130 const T *const ppixel = &pixel;
philpem@5 11131 return !is_empty() && ppixel>=data && ppixel<data+size();
philpem@5 11132 }
philpem@5 11133
philpem@5 11134 //! Read a pixel value with Dirichlet boundary conditions.
philpem@5 11135 T& at(const int off, const T out_val) {
philpem@5 11136 return (off<0 || off>=(int)size())?(cimg::temporary(out_val)=out_val):(*this)[off];
philpem@5 11137 }
philpem@5 11138
philpem@5 11139 T at(const int off, const T out_val) const {
philpem@5 11140 return (off<0 || off>=(int)size())?out_val:(*this)[off];
philpem@5 11141 }
philpem@5 11142
philpem@5 11143 //! Read a pixel value with Neumann boundary conditions.
philpem@5 11144 T& at(const int off) {
philpem@5 11145 if (!size())
philpem@5 11146 throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
philpem@5 11147 pixel_type());
philpem@5 11148 return _at(off);
philpem@5 11149 }
philpem@5 11150
philpem@5 11151 T at(const int off) const {
philpem@5 11152 if (!size())
philpem@5 11153 throw CImgInstanceException("CImg<%s>::at() : Instance image is empty.",
philpem@5 11154 pixel_type());
philpem@5 11155 return _at(off);
philpem@5 11156 }
philpem@5 11157
philpem@5 11158 T& _at(const int off) {
philpem@5 11159 const unsigned int siz = (unsigned int)size();
philpem@5 11160 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
philpem@5 11161 }
philpem@5 11162
philpem@5 11163 T _at(const int off) const {
philpem@5 11164 const unsigned int siz = (unsigned int)size();
philpem@5 11165 return (*this)[off<0?0:(unsigned int)off>=siz?siz-1:off];
philpem@5 11166 }
philpem@5 11167
philpem@5 11168 //! Read a pixel value with Dirichlet boundary conditions.
philpem@5 11169 T& atXYZV(const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 11170 return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?
philpem@5 11171 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
philpem@5 11172 }
philpem@5 11173
philpem@5 11174 T atXYZV(const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 11175 return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v);
philpem@5 11176 }
philpem@5 11177
philpem@5 11178 //! Read a pixel value with Neumann boundary conditions.
philpem@5 11179 T& atXYZV(const int x, const int y, const int z, const int v) {
philpem@5 11180 if (is_empty())
philpem@5 11181 throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
philpem@5 11182 pixel_type());
philpem@5 11183 return _atXYZV(x,y,z,v);
philpem@5 11184 }
philpem@5 11185
philpem@5 11186 T atXYZV(const int x, const int y, const int z, const int v) const {
philpem@5 11187 if (is_empty())
philpem@5 11188 throw CImgInstanceException("CImg<%s>::atXYZV() : Instance image is empty.",
philpem@5 11189 pixel_type());
philpem@5 11190 return _atXYZV(x,y,z,v);
philpem@5 11191 }
philpem@5 11192
philpem@5 11193 T& _atXYZV(const int x, const int y, const int z, const int v) {
philpem@5 11194 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
philpem@5 11195 z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
philpem@5 11196 }
philpem@5 11197
philpem@5 11198 T _atXYZV(const int x, const int y, const int z, const int v) const {
philpem@5 11199 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),
philpem@5 11200 z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v));
philpem@5 11201 }
philpem@5 11202
philpem@5 11203 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c x,\c y,\c z).
philpem@5 11204 T& atXYZ(const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 11205 return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?
philpem@5 11206 (cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
philpem@5 11207 }
philpem@5 11208
philpem@5 11209 T atXYZ(const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 11210 return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v);
philpem@5 11211 }
philpem@5 11212
philpem@5 11213 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z).
philpem@5 11214 T& atXYZ(const int x, const int y, const int z, const int v=0) {
philpem@5 11215 if (is_empty())
philpem@5 11216 throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
philpem@5 11217 pixel_type());
philpem@5 11218 return _atXYZ(x,y,z,v);
philpem@5 11219 }
philpem@5 11220
philpem@5 11221 T atXYZ(const int x, const int y, const int z, const int v=0) const {
philpem@5 11222 if (is_empty())
philpem@5 11223 throw CImgInstanceException("CImg<%s>::atXYZ() : Instance image is empty.",
philpem@5 11224 pixel_type());
philpem@5 11225 return _atXYZ(x,y,z,v);
philpem@5 11226 }
philpem@5 11227
philpem@5 11228 T& _atXYZ(const int x, const int y, const int z, const int v=0) {
philpem@5 11229 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
philpem@5 11230 z<0?0:(z>=dimz()?dimz()-1:z),v);
philpem@5 11231 }
philpem@5 11232
philpem@5 11233 T _atXYZ(const int x, const int y, const int z, const int v=0) const {
philpem@5 11234 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y<0?0:(y>=dimy()?dimy()-1:y),
philpem@5 11235 z<0?0:(z>=dimz()?dimz()-1:z),v);
philpem@5 11236 }
philpem@5 11237
philpem@5 11238 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c x,\c y).
philpem@5 11239 T& atXY(const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 11240 return (x<0 || y<0 || x>=dimx() || y>=dimy())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
philpem@5 11241 }
philpem@5 11242
philpem@5 11243 T atXY(const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 11244 return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v);
philpem@5 11245 }
philpem@5 11246
philpem@5 11247 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c x,\c y).
philpem@5 11248 T& atXY(const int x, const int y, const int z=0, const int v=0) {
philpem@5 11249 if (is_empty())
philpem@5 11250 throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
philpem@5 11251 pixel_type());
philpem@5 11252 return _atXY(x,y,z,v);
philpem@5 11253 }
philpem@5 11254
philpem@5 11255 T atXY(const int x, const int y, const int z=0, const int v=0) const {
philpem@5 11256 if (is_empty())
philpem@5 11257 throw CImgInstanceException("CImg<%s>::atXY() : Instance image is empty.",
philpem@5 11258 pixel_type());
philpem@5 11259 return _atXY(x,y,z,v);
philpem@5 11260 }
philpem@5 11261
philpem@5 11262 T& _atXY(const int x, const int y, const int z=0, const int v=0) {
philpem@5 11263 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
philpem@5 11264 }
philpem@5 11265
philpem@5 11266 T _atXY(const int x, const int y, const int z=0, const int v=0) const {
philpem@5 11267 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v);
philpem@5 11268 }
philpem@5 11269
philpem@5 11270 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c x).
philpem@5 11271 T& atX(const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 11272 return (x<0 || x>=dimx())?(cimg::temporary(out_val)=out_val):(*this)(x,y,z,v);
philpem@5 11273 }
philpem@5 11274
philpem@5 11275 T atX(const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 11276 return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v);
philpem@5 11277 }
philpem@5 11278
philpem@5 11279 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c x).
philpem@5 11280 T& atX(const int x, const int y=0, const int z=0, const int v=0) {
philpem@5 11281 if (is_empty())
philpem@5 11282 throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
philpem@5 11283 pixel_type());
philpem@5 11284 return _atX(x,y,z,v);
philpem@5 11285 }
philpem@5 11286
philpem@5 11287 T atX(const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 11288 if (is_empty())
philpem@5 11289 throw CImgInstanceException("CImg<%s>::atX() : Instance image is empty.",
philpem@5 11290 pixel_type());
philpem@5 11291 return _atX(x,y,z,v);
philpem@5 11292 }
philpem@5 11293
philpem@5 11294 T& _atX(const int x, const int y=0, const int z=0, const int v=0) {
philpem@5 11295 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
philpem@5 11296 }
philpem@5 11297
philpem@5 11298 T _atX(const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 11299 return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v);
philpem@5 11300 }
philpem@5 11301
philpem@5 11302 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions.
philpem@5 11303 Tfloat linear_atXYZV(const float fx, const float fy, const float fz, const float fv, const T out_val) const {
philpem@5 11304 const int
philpem@5 11305 x = (int)fx-(fx>=0?0:1), nx = x+1,
philpem@5 11306 y = (int)fy-(fy>=0?0:1), ny = y+1,
philpem@5 11307 z = (int)fz-(fz>=0?0:1), nz = z+1,
philpem@5 11308 v = (int)fv-(fv>=0?0:1), nv = v+1;
philpem@5 11309 const float
philpem@5 11310 dx = fx-x,
philpem@5 11311 dy = fy-y,
philpem@5 11312 dz = fz-z,
philpem@5 11313 dv = fv-v;
philpem@5 11314 const Tfloat
philpem@5 11315 Icccc = (Tfloat)atXYZV(x,y,z,v,out_val), Inccc = (Tfloat)atXYZV(nx,y,z,v,out_val),
philpem@5 11316 Icncc = (Tfloat)atXYZV(x,ny,z,v,out_val), Inncc = (Tfloat)atXYZV(nx,ny,z,v,out_val),
philpem@5 11317 Iccnc = (Tfloat)atXYZV(x,y,nz,v,out_val), Incnc = (Tfloat)atXYZV(nx,y,nz,v,out_val),
philpem@5 11318 Icnnc = (Tfloat)atXYZV(x,ny,nz,v,out_val), Innnc = (Tfloat)atXYZV(nx,ny,nz,v,out_val),
philpem@5 11319 Icccn = (Tfloat)atXYZV(x,y,z,nv,out_val), Inccn = (Tfloat)atXYZV(nx,y,z,nv,out_val),
philpem@5 11320 Icncn = (Tfloat)atXYZV(x,ny,z,nv,out_val), Inncn = (Tfloat)atXYZV(nx,ny,z,nv,out_val),
philpem@5 11321 Iccnn = (Tfloat)atXYZV(x,y,nz,nv,out_val), Incnn = (Tfloat)atXYZV(nx,y,nz,nv,out_val),
philpem@5 11322 Icnnn = (Tfloat)atXYZV(x,ny,nz,nv,out_val), Innnn = (Tfloat)atXYZV(nx,ny,nz,nv,out_val);
philpem@5 11323 return Icccc +
philpem@5 11324 dx*(Inccc-Icccc +
philpem@5 11325 dy*(Icccc+Inncc-Icncc-Inccc +
philpem@5 11326 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
philpem@5 11327 dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
philpem@5 11328 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
philpem@5 11329 dz*(Icccc+Incnc-Iccnc-Inccc +
philpem@5 11330 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
philpem@5 11331 dv*(Icccc+Inccn-Inccc-Icccn)) +
philpem@5 11332 dy*(Icncc-Icccc +
philpem@5 11333 dz*(Icccc+Icnnc-Iccnc-Icncc +
philpem@5 11334 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
philpem@5 11335 dv*(Icccc+Icncn-Icncc-Icccn)) +
philpem@5 11336 dz*(Iccnc-Icccc +
philpem@5 11337 dv*(Icccc+Iccnn-Iccnc-Icccn)) +
philpem@5 11338 dv*(Icccn-Icccc);
philpem@5 11339 }
philpem@5 11340
philpem@5 11341 //! Read a pixel value using linear interpolation and Neumann boundary conditions.
philpem@5 11342 Tfloat linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
philpem@5 11343 if (is_empty())
philpem@5 11344 throw CImgInstanceException("CImg<%s>::linear_atXYZV() : Instance image is empty.",
philpem@5 11345 pixel_type());
philpem@5 11346 return _linear_atXYZV(fx,fy,fz,fv);
philpem@5 11347 }
philpem@5 11348
philpem@5 11349 Tfloat _linear_atXYZV(const float fx, const float fy=0, const float fz=0, const float fv=0) const {
philpem@5 11350 const float
philpem@5 11351 nfx = fx<0?0:(fx>width-1?width-1:fx),
philpem@5 11352 nfy = fy<0?0:(fy>height-1?height-1:fy),
philpem@5 11353 nfz = fz<0?0:(fz>depth-1?depth-1:fz),
philpem@5 11354 nfv = fv<0?0:(fv>dim-1?dim-1:fv);
philpem@5 11355 const unsigned int
philpem@5 11356 x = (unsigned int)nfx,
philpem@5 11357 y = (unsigned int)nfy,
philpem@5 11358 z = (unsigned int)nfz,
philpem@5 11359 v = (unsigned int)nfv;
philpem@5 11360 const float
philpem@5 11361 dx = nfx-x,
philpem@5 11362 dy = nfy-y,
philpem@5 11363 dz = nfz-z,
philpem@5 11364 dv = nfv-v;
philpem@5 11365 const unsigned int
philpem@5 11366 nx = dx>0?x+1:x,
philpem@5 11367 ny = dy>0?y+1:y,
philpem@5 11368 nz = dz>0?z+1:z,
philpem@5 11369 nv = dv>0?v+1:v;
philpem@5 11370 const Tfloat
philpem@5 11371 Icccc = (Tfloat)(*this)(x,y,z,v), Inccc = (Tfloat)(*this)(nx,y,z,v),
philpem@5 11372 Icncc = (Tfloat)(*this)(x,ny,z,v), Inncc = (Tfloat)(*this)(nx,ny,z,v),
philpem@5 11373 Iccnc = (Tfloat)(*this)(x,y,nz,v), Incnc = (Tfloat)(*this)(nx,y,nz,v),
philpem@5 11374 Icnnc = (Tfloat)(*this)(x,ny,nz,v), Innnc = (Tfloat)(*this)(nx,ny,nz,v),
philpem@5 11375 Icccn = (Tfloat)(*this)(x,y,z,nv), Inccn = (Tfloat)(*this)(nx,y,z,nv),
philpem@5 11376 Icncn = (Tfloat)(*this)(x,ny,z,nv), Inncn = (Tfloat)(*this)(nx,ny,z,nv),
philpem@5 11377 Iccnn = (Tfloat)(*this)(x,y,nz,nv), Incnn = (Tfloat)(*this)(nx,y,nz,nv),
philpem@5 11378 Icnnn = (Tfloat)(*this)(x,ny,nz,nv), Innnn = (Tfloat)(*this)(nx,ny,nz,nv);
philpem@5 11379 return Icccc +
philpem@5 11380 dx*(Inccc-Icccc +
philpem@5 11381 dy*(Icccc+Inncc-Icncc-Inccc +
philpem@5 11382 dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc +
philpem@5 11383 dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) +
philpem@5 11384 dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) +
philpem@5 11385 dz*(Icccc+Incnc-Iccnc-Inccc +
philpem@5 11386 dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) +
philpem@5 11387 dv*(Icccc+Inccn-Inccc-Icccn)) +
philpem@5 11388 dy*(Icncc-Icccc +
philpem@5 11389 dz*(Icccc+Icnnc-Iccnc-Icncc +
philpem@5 11390 dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) +
philpem@5 11391 dv*(Icccc+Icncn-Icncc-Icccn)) +
philpem@5 11392 dz*(Iccnc-Icccc +
philpem@5 11393 dv*(Icccc+Iccnn-Iccnc-Icccn)) +
philpem@5 11394 dv*(Icccn-Icccc);
philpem@5 11395 }
philpem@5 11396
philpem@5 11397 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first three coordinates).
philpem@5 11398 Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int v, const T out_val) const {
philpem@5 11399 const int
philpem@5 11400 x = (int)fx-(fx>=0?0:1), nx = x+1,
philpem@5 11401 y = (int)fy-(fy>=0?0:1), ny = y+1,
philpem@5 11402 z = (int)fz-(fz>=0?0:1), nz = z+1;
philpem@5 11403 const float
philpem@5 11404 dx = fx-x,
philpem@5 11405 dy = fy-y,
philpem@5 11406 dz = fz-z;
philpem@5 11407 const Tfloat
philpem@5 11408 Iccc = (Tfloat)atXYZ(x,y,z,v,out_val), Incc = (Tfloat)atXYZ(nx,y,z,v,out_val),
philpem@5 11409 Icnc = (Tfloat)atXYZ(x,ny,z,v,out_val), Innc = (Tfloat)atXYZ(nx,ny,z,v,out_val),
philpem@5 11410 Iccn = (Tfloat)atXYZ(x,y,nz,v,out_val), Incn = (Tfloat)atXYZ(nx,y,nz,v,out_val),
philpem@5 11411 Icnn = (Tfloat)atXYZ(x,ny,nz,v,out_val), Innn = (Tfloat)atXYZ(nx,ny,nz,v,out_val);
philpem@5 11412 return Iccc +
philpem@5 11413 dx*(Incc-Iccc +
philpem@5 11414 dy*(Iccc+Innc-Icnc-Incc +
philpem@5 11415 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
philpem@5 11416 dz*(Iccc+Incn-Iccn-Incc)) +
philpem@5 11417 dy*(Icnc-Iccc +
philpem@5 11418 dz*(Iccc+Icnn-Iccn-Icnc)) +
philpem@5 11419 dz*(Iccn-Iccc);
philpem@5 11420 }
philpem@5 11421
philpem@5 11422 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first three coordinates).
philpem@5 11423 Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
philpem@5 11424 if (is_empty())
philpem@5 11425 throw CImgInstanceException("CImg<%s>::linear_atXYZ() : Instance image is empty.",
philpem@5 11426 pixel_type());
philpem@5 11427 return _linear_atXYZ(fx,fy,fz,v);
philpem@5 11428 }
philpem@5 11429
philpem@5 11430 Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int v=0) const {
philpem@5 11431 const float
philpem@5 11432 nfx = fx<0?0:(fx>width-1?width-1:fx),
philpem@5 11433 nfy = fy<0?0:(fy>height-1?height-1:fy),
philpem@5 11434 nfz = fz<0?0:(fz>depth-1?depth-1:fz);
philpem@5 11435 const unsigned int
philpem@5 11436 x = (unsigned int)nfx,
philpem@5 11437 y = (unsigned int)nfy,
philpem@5 11438 z = (unsigned int)nfz;
philpem@5 11439 const float
philpem@5 11440 dx = nfx-x,
philpem@5 11441 dy = nfy-y,
philpem@5 11442 dz = nfz-z;
philpem@5 11443 const unsigned int
philpem@5 11444 nx = dx>0?x+1:x,
philpem@5 11445 ny = dy>0?y+1:y,
philpem@5 11446 nz = dz>0?z+1:z;
philpem@5 11447 const Tfloat
philpem@5 11448 Iccc = (Tfloat)(*this)(x,y,z,v), Incc = (Tfloat)(*this)(nx,y,z,v),
philpem@5 11449 Icnc = (Tfloat)(*this)(x,ny,z,v), Innc = (Tfloat)(*this)(nx,ny,z,v),
philpem@5 11450 Iccn = (Tfloat)(*this)(x,y,nz,v), Incn = (Tfloat)(*this)(nx,y,nz,v),
philpem@5 11451 Icnn = (Tfloat)(*this)(x,ny,nz,v), Innn = (Tfloat)(*this)(nx,ny,nz,v);
philpem@5 11452 return Iccc +
philpem@5 11453 dx*(Incc-Iccc +
philpem@5 11454 dy*(Iccc+Innc-Icnc-Incc +
philpem@5 11455 dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) +
philpem@5 11456 dz*(Iccc+Incn-Iccn-Incc)) +
philpem@5 11457 dy*(Icnc-Iccc +
philpem@5 11458 dz*(Iccc+Icnn-Iccn-Icnc)) +
philpem@5 11459 dz*(Iccn-Iccc);
philpem@5 11460 }
philpem@5 11461
philpem@5 11462 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first two coordinates).
philpem@5 11463 Tfloat linear_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
philpem@5 11464 const int
philpem@5 11465 x = (int)fx-(fx>=0?0:1), nx = x+1,
philpem@5 11466 y = (int)fy-(fy>=0?0:1), ny = y+1;
philpem@5 11467 const float
philpem@5 11468 dx = fx-x,
philpem@5 11469 dy = fy-y;
philpem@5 11470 const Tfloat
philpem@5 11471 Icc = (Tfloat)atXY(x,y,z,v,out_val), Inc = (Tfloat)atXY(nx,y,z,v,out_val),
philpem@5 11472 Icn = (Tfloat)atXY(x,ny,z,v,out_val), Inn = (Tfloat)atXY(nx,ny,z,v,out_val);
philpem@5 11473 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
philpem@5 11474 }
philpem@5 11475
philpem@5 11476 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first two coordinates).
philpem@5 11477 Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
philpem@5 11478 if (is_empty())
philpem@5 11479 throw CImgInstanceException("CImg<%s>::linear_atXY() : Instance image is empty.",
philpem@5 11480 pixel_type());
philpem@5 11481 return _linear_atXY(fx,fy,z,v);
philpem@5 11482 }
philpem@5 11483
philpem@5 11484 Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
philpem@5 11485 const float
philpem@5 11486 nfx = fx<0?0:(fx>width-1?width-1:fx),
philpem@5 11487 nfy = fy<0?0:(fy>height-1?height-1:fy);
philpem@5 11488 const unsigned int
philpem@5 11489 x = (unsigned int)nfx,
philpem@5 11490 y = (unsigned int)nfy;
philpem@5 11491 const float
philpem@5 11492 dx = nfx-x,
philpem@5 11493 dy = nfy-y;
philpem@5 11494 const unsigned int
philpem@5 11495 nx = dx>0?x+1:x,
philpem@5 11496 ny = dy>0?y+1:y;
philpem@5 11497 const Tfloat
philpem@5 11498 Icc = (Tfloat)(*this)(x,y,z,v), Inc = (Tfloat)(*this)(nx,y,z,v),
philpem@5 11499 Icn = (Tfloat)(*this)(x,ny,z,v), Inn = (Tfloat)(*this)(nx,ny,z,v);
philpem@5 11500 return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc);
philpem@5 11501 }
philpem@5 11502
philpem@5 11503 //! Read a pixel value using linear interpolation and Dirichlet boundary conditions (first coordinate).
philpem@5 11504 Tfloat linear_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
philpem@5 11505 const int
philpem@5 11506 x = (int)fx-(fx>=0?0:1), nx = x+1;
philpem@5 11507 const float
philpem@5 11508 dx = fx-x;
philpem@5 11509 const Tfloat
philpem@5 11510 Ic = (Tfloat)atX(x,y,z,v,out_val), In = (Tfloat)atXY(nx,y,z,v,out_val);
philpem@5 11511 return Ic + dx*(In-Ic);
philpem@5 11512 }
philpem@5 11513
philpem@5 11514 //! Read a pixel value using linear interpolation and Neumann boundary conditions (first coordinate).
philpem@5 11515 Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
philpem@5 11516 if (is_empty())
philpem@5 11517 throw CImgInstanceException("CImg<%s>::linear_atX() : Instance image is empty.",
philpem@5 11518 pixel_type());
philpem@5 11519 return _linear_atX(fx,y,z,v);
philpem@5 11520 }
philpem@5 11521
philpem@5 11522 Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
philpem@5 11523 const float
philpem@5 11524 nfx = fx<0?0:(fx>width-1?width-1:fx);
philpem@5 11525 const unsigned int
philpem@5 11526 x = (unsigned int)nfx;
philpem@5 11527 const float
philpem@5 11528 dx = nfx-x;
philpem@5 11529 const unsigned int
philpem@5 11530 nx = dx>0?x+1:x;
philpem@5 11531 const Tfloat
philpem@5 11532 Ic = (Tfloat)(*this)(x,y,z,v), In = (Tfloat)(*this)(nx,y,z,v);
philpem@5 11533 return Ic + dx*(In-Ic);
philpem@5 11534 }
philpem@5 11535
philpem@5 11536 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions.
philpem@5 11537 Tfloat cubic_atXY(const float fx, const float fy, const int z, const int v, const T out_val) const {
philpem@5 11538 const int
philpem@5 11539 x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2,
philpem@5 11540 y = (int)fy-(fy>=0?0:1), py = y-1, ny = y+1, ay = y+2;
philpem@5 11541 const float
philpem@5 11542 dx = fx-x, dx2 = dx*dx, dx3 = dx2*dx,
philpem@5 11543 dy = fy-y;
philpem@5 11544 const Tfloat
philpem@5 11545 Ipp = (Tfloat)atXY(px,py,z,v,out_val), Icp = (Tfloat)atXY(x,py,z,v,out_val),
philpem@5 11546 Inp = (Tfloat)atXY(nx,py,z,v,out_val), Iap = (Tfloat)atXY(ax,py,z,v,out_val),
philpem@5 11547 Ipc = (Tfloat)atXY(px,y,z,v,out_val), Icc = (Tfloat)atXY(x,y,z,v,out_val),
philpem@5 11548 Inc = (Tfloat)atXY(nx,y,z,v,out_val), Iac = (Tfloat)atXY(ax,y,z,v,out_val),
philpem@5 11549 Ipn = (Tfloat)atXY(px,ny,z,v,out_val), Icn = (Tfloat)atXY(x,ny,z,v,out_val),
philpem@5 11550 Inn = (Tfloat)atXY(nx,ny,z,v,out_val), Ian = (Tfloat)atXY(ax,ny,z,v,out_val),
philpem@5 11551 Ipa = (Tfloat)atXY(px,ay,z,v,out_val), Ica = (Tfloat)atXY(x,ay,z,v,out_val),
philpem@5 11552 Ina = (Tfloat)atXY(nx,ay,z,v,out_val), Iaa = (Tfloat)atXY(ax,ay,z,v,out_val),
philpem@5 11553 valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
philpem@5 11554 valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
philpem@5 11555 u0p = Icp - Ipp,
philpem@5 11556 u1p = Iap - Inp,
philpem@5 11557 ap = 2*(Icp-Inp) + u0p + u1p,
philpem@5 11558 bp = 3*(Inp-Icp) - 2*u0p - u1p,
philpem@5 11559 u0c = Icc - Ipc,
philpem@5 11560 u1c = Iac - Inc,
philpem@5 11561 ac = 2*(Icc-Inc) + u0c + u1c,
philpem@5 11562 bc = 3*(Inc-Icc) - 2*u0c - u1c,
philpem@5 11563 u0n = Icn - Ipn,
philpem@5 11564 u1n = Ian - Inn,
philpem@5 11565 an = 2*(Icn-Inn) + u0n + u1n,
philpem@5 11566 bn = 3*(Inn-Icn) - 2*u0n - u1n,
philpem@5 11567 u0a = Ica - Ipa,
philpem@5 11568 u1a = Iaa - Ina,
philpem@5 11569 aa = 2*(Ica-Ina) + u0a + u1a,
philpem@5 11570 ba = 3*(Ina-Ica) - 2*u0a - u1a,
philpem@5 11571 valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
philpem@5 11572 valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
philpem@5 11573 valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
philpem@5 11574 vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
philpem@5 11575 u0 = valc - valp,
philpem@5 11576 u1 = vala - valn,
philpem@5 11577 a = 2*(valc-valn) + u0 + u1,
philpem@5 11578 b = 3*(valn-valc) - 2*u0 - u1,
philpem@5 11579 val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
philpem@5 11580 return val<valm?valm:(val>valM?valM:val);
philpem@5 11581 }
philpem@5 11582
philpem@5 11583 //! Read a pixel value using cubic interpolation and Neumann boundary conditions.
philpem@5 11584 Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
philpem@5 11585 if (is_empty())
philpem@5 11586 throw CImgInstanceException("CImg<%s>::cubic_atXY() : Instance image is empty.",
philpem@5 11587 pixel_type());
philpem@5 11588 return _cubic_atXY(fx,fy,z,v);
philpem@5 11589 }
philpem@5 11590
philpem@5 11591 Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int v=0) const {
philpem@5 11592 const float
philpem@5 11593 nfx = fx<0?0:(fx>width-1?width-1:fx),
philpem@5 11594 nfy = fy<0?0:(fy>height-1?height-1:fy);
philpem@5 11595 const int
philpem@5 11596 x = (int)nfx,
philpem@5 11597 y = (int)nfy;
philpem@5 11598 const float
philpem@5 11599 dx = nfx-x, dx2 = dx*dx, dx3 = dx2*dx,
philpem@5 11600 dy = nfy-y;
philpem@5 11601 const int
philpem@5 11602 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2,
philpem@5 11603 py = y-1<0?0:y-1, ny = dy>0?y+1:y, ay = y+2>=dimy()?dimy()-1:y+2;
philpem@5 11604 const Tfloat
philpem@5 11605 Ipp = (Tfloat)(*this)(px,py,z,v), Icp = (Tfloat)(*this)(x,py,z,v),
philpem@5 11606 Inp = (Tfloat)(*this)(nx,py,z,v), Iap = (Tfloat)(*this)(ax,py,z,v),
philpem@5 11607 Ipc = (Tfloat)(*this)(px,y,z,v), Icc = (Tfloat)(*this)(x,y,z,v),
philpem@5 11608 Inc = (Tfloat)(*this)(nx,y,z,v), Iac = (Tfloat)(*this)(ax,y,z,v),
philpem@5 11609 Ipn = (Tfloat)(*this)(px,ny,z,v), Icn = (Tfloat)(*this)(x,ny,z,v),
philpem@5 11610 Inn = (Tfloat)(*this)(nx,ny,z,v), Ian = (Tfloat)(*this)(ax,ny,z,v),
philpem@5 11611 Ipa = (Tfloat)(*this)(px,ay,z,v), Ica = (Tfloat)(*this)(x,ay,z,v),
philpem@5 11612 Ina = (Tfloat)(*this)(nx,ay,z,v), Iaa = (Tfloat)(*this)(ax,ay,z,v),
philpem@5 11613 valm = cimg::min(cimg::min(Ipp,Icp,Inp,Iap),cimg::min(Ipc,Icc,Inc,Iac),cimg::min(Ipn,Icn,Inn,Ian),cimg::min(Ipa,Ica,Ina,Iaa)),
philpem@5 11614 valM = cimg::max(cimg::max(Ipp,Icp,Inp,Iap),cimg::max(Ipc,Icc,Inc,Iac),cimg::max(Ipn,Icn,Inn,Ian),cimg::max(Ipa,Ica,Ina,Iaa)),
philpem@5 11615 u0p = Icp - Ipp,
philpem@5 11616 u1p = Iap - Inp,
philpem@5 11617 ap = 2*(Icp-Inp) + u0p + u1p,
philpem@5 11618 bp = 3*(Inp-Icp) - 2*u0p - u1p,
philpem@5 11619 u0c = Icc - Ipc,
philpem@5 11620 u1c = Iac - Inc,
philpem@5 11621 ac = 2*(Icc-Inc) + u0c + u1c,
philpem@5 11622 bc = 3*(Inc-Icc) - 2*u0c - u1c,
philpem@5 11623 u0n = Icn - Ipn,
philpem@5 11624 u1n = Ian - Inn,
philpem@5 11625 an = 2*(Icn-Inn) + u0n + u1n,
philpem@5 11626 bn = 3*(Inn-Icn) - 2*u0n - u1n,
philpem@5 11627 u0a = Ica - Ipa,
philpem@5 11628 u1a = Iaa - Ina,
philpem@5 11629 aa = 2*(Ica-Ina) + u0a + u1a,
philpem@5 11630 ba = 3*(Ina-Ica) - 2*u0a - u1a,
philpem@5 11631 valp = ap*dx3 + bp*dx2 + u0p*dx + Icp,
philpem@5 11632 valc = ac*dx3 + bc*dx2 + u0c*dx + Icc,
philpem@5 11633 valn = an*dx3 + bn*dx2 + u0n*dx + Icn,
philpem@5 11634 vala = aa*dx3 + ba*dx2 + u0a*dx + Ica,
philpem@5 11635 u0 = valc - valp,
philpem@5 11636 u1 = vala - valn,
philpem@5 11637 a = 2*(valc-valn) + u0 + u1,
philpem@5 11638 b = 3*(valn-valc) - 2*u0 - u1,
philpem@5 11639 val = a*dy*dy*dy + b*dy*dy + u0*dy + valc;
philpem@5 11640 return val<valm?valm:(val>valM?valM:val);
philpem@5 11641 }
philpem@5 11642
philpem@5 11643 //! Read a pixel value using cubic interpolation and Dirichlet boundary conditions (first coordinates).
philpem@5 11644 Tfloat cubic_atX(const float fx, const int y, const int z, const int v, const T out_val) const {
philpem@5 11645 const int
philpem@5 11646 x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = x+2;
philpem@5 11647 const float
philpem@5 11648 dx = fx-x;
philpem@5 11649 const Tfloat
philpem@5 11650 Ip = (Tfloat)atX(px,y,z,v,out_val), Ic = (Tfloat)atX(x,y,z,v,out_val),
philpem@5 11651 In = (Tfloat)atX(nx,y,z,v,out_val), Ia = (Tfloat)atX(ax,y,z,v,out_val),
philpem@5 11652 valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
philpem@5 11653 u0 = Ic - Ip,
philpem@5 11654 u1 = Ia - In,
philpem@5 11655 a = 2*(Ic-In) + u0 + u1,
philpem@5 11656 b = 3*(In-Ic) - 2*u0 - u1,
philpem@5 11657 val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
philpem@5 11658 return val<valm?valm:(val>valM?valM:val);
philpem@5 11659 }
philpem@5 11660
philpem@5 11661 //! Read a pixel value using cubic interpolation and Neumann boundary conditions (first coordinates).
philpem@5 11662 Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
philpem@5 11663 if (is_empty())
philpem@5 11664 throw CImgInstanceException("CImg<%s>::cubic_atX() : Instance image is empty.",
philpem@5 11665 pixel_type());
philpem@5 11666 return _cubic_atX(fx,y,z,v);
philpem@5 11667 }
philpem@5 11668
philpem@5 11669 Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int v=0) const {
philpem@5 11670 const float
philpem@5 11671 nfx = fx<0?0:(fx>width-1?width-1:fx);
philpem@5 11672 const int
philpem@5 11673 x = (int)nfx;
philpem@5 11674 const float
philpem@5 11675 dx = nfx-x;
philpem@5 11676 const int
philpem@5 11677 px = x-1<0?0:x-1, nx = dx>0?x+1:x, ax = x+2>=dimx()?dimx()-1:x+2;
philpem@5 11678 const Tfloat
philpem@5 11679 Ip = (Tfloat)(*this)(px,y,z,v), Ic = (Tfloat)(*this)(x,y,z,v),
philpem@5 11680 In = (Tfloat)(*this)(nx,y,z,v), Ia = (Tfloat)(*this)(ax,y,z,v),
philpem@5 11681 valm = cimg::min(Ip,In,Ic,Ia), valM = cimg::max(Ip,In,Ic,Ia),
philpem@5 11682 u0 = Ic - Ip,
philpem@5 11683 u1 = Ia - In,
philpem@5 11684 a = 2*(Ic-In) + u0 + u1,
philpem@5 11685 b = 3*(In-Ic) - 2*u0 - u1,
philpem@5 11686 val = a*dx*dx*dx + b*dx*dx + u0*dx + Ic;
philpem@5 11687 return val<valm?valm:(val>valM?valM:val);
philpem@5 11688 }
philpem@5 11689
philpem@5 11690 //! Set a pixel value, with 3D float coordinates, using linear interpolation.
philpem@5 11691 CImg& set_linear_atXYZ(const T& val, const float fx, const float fy=0, const float fz=0, const int v=0,
philpem@5 11692 const bool add=false) {
philpem@5 11693 const int
philpem@5 11694 x = (int)fx-(fx>=0?0:1), nx = x+1,
philpem@5 11695 y = (int)fy-(fy>=0?0:1), ny = y+1,
philpem@5 11696 z = (int)fz-(fz>=0?0:1), nz = z+1;
philpem@5 11697 const float
philpem@5 11698 dx = fx-x,
philpem@5 11699 dy = fy-y,
philpem@5 11700 dz = fz-z;
philpem@5 11701 if (v>=0 && v<dimv()) {
philpem@5 11702 if (z>=0 && z<dimz()) {
philpem@5 11703 if (y>=0 && y<dimy()) {
philpem@5 11704 if (x>=0 && x<dimx()) {
philpem@5 11705 const float w1 = (1-dx)*(1-dy)*(1-dz), w2 = add?1:(1-w1);
philpem@5 11706 (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
philpem@5 11707 }
philpem@5 11708 if (nx>=0 && nx<dimx()) {
philpem@5 11709 const float w1 = dx*(1-dy)*(1-dz), w2 = add?1:(1-w1);
philpem@5 11710 (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
philpem@5 11711 }
philpem@5 11712 }
philpem@5 11713 if (ny>=0 && ny<dimy()) {
philpem@5 11714 if (x>=0 && x<dimx()) {
philpem@5 11715 const float w1 = (1-dx)*dy*(1-dz), w2 = add?1:(1-w1);
philpem@5 11716 (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
philpem@5 11717 }
philpem@5 11718 if (nx>=0 && nx<dimx()) {
philpem@5 11719 const float w1 = dx*dy*(1-dz), w2 = add?1:(1-w1);
philpem@5 11720 (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
philpem@5 11721 }
philpem@5 11722 }
philpem@5 11723 }
philpem@5 11724 if (nz>=0 && nz<dimz()) {
philpem@5 11725 if (y>=0 && y<dimy()) {
philpem@5 11726 if (x>=0 && x<dimx()) {
philpem@5 11727 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
philpem@5 11728 (*this)(x,y,nz,v) = (T)(w1*val + w2*(*this)(x,y,nz,v));
philpem@5 11729 }
philpem@5 11730 if (nx>=0 && nx<dimx()) {
philpem@5 11731 const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
philpem@5 11732 (*this)(nx,y,nz,v) = (T)(w1*val + w2*(*this)(nx,y,nz,v));
philpem@5 11733 }
philpem@5 11734 }
philpem@5 11735 if (ny>=0 && ny<dimy()) {
philpem@5 11736 if (x>=0 && x<dimx()) {
philpem@5 11737 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
philpem@5 11738 (*this)(x,ny,nz,v) = (T)(w1*val + w2*(*this)(x,ny,nz,v));
philpem@5 11739 }
philpem@5 11740 if (nx>=0 && nx<dimx()) {
philpem@5 11741 const float w1 = dx*dy, w2 = add?1:(1-w1);
philpem@5 11742 (*this)(nx,ny,nz,v) = (T)(w1*val + w2*(*this)(nx,ny,nz,v));
philpem@5 11743 }
philpem@5 11744 }
philpem@5 11745 }
philpem@5 11746 }
philpem@5 11747 return *this;
philpem@5 11748 }
philpem@5 11749
philpem@5 11750 //! Set a pixel value, with 2D float coordinates, using linear interpolation.
philpem@5 11751 CImg& set_linear_atXY(const T& val, const float fx, const float fy=0, const int z=0, const int v=0,
philpem@5 11752 const bool add=false) {
philpem@5 11753 const int
philpem@5 11754 x = (int)fx-(fx>=0?0:1), nx = x+1,
philpem@5 11755 y = (int)fy-(fy>=0?0:1), ny = y+1;
philpem@5 11756 const float
philpem@5 11757 dx = fx-x,
philpem@5 11758 dy = fy-y;
philpem@5 11759 if (z>=0 && z<dimz() && v>=0 && v<dimv()) {
philpem@5 11760 if (y>=0 && y<dimy()) {
philpem@5 11761 if (x>=0 && x<dimx()) {
philpem@5 11762 const float w1 = (1-dx)*(1-dy), w2 = add?1:(1-w1);
philpem@5 11763 (*this)(x,y,z,v) = (T)(w1*val + w2*(*this)(x,y,z,v));
philpem@5 11764 }
philpem@5 11765 if (nx>=0 && nx<dimx()) {
philpem@5 11766 const float w1 = dx*(1-dy), w2 = add?1:(1-w1);
philpem@5 11767 (*this)(nx,y,z,v) = (T)(w1*val + w2*(*this)(nx,y,z,v));
philpem@5 11768 }
philpem@5 11769 }
philpem@5 11770 if (ny>=0 && ny<dimy()) {
philpem@5 11771 if (x>=0 && x<dimx()) {
philpem@5 11772 const float w1 = (1-dx)*dy, w2 = add?1:(1-w1);
philpem@5 11773 (*this)(x,ny,z,v) = (T)(w1*val + w2*(*this)(x,ny,z,v));
philpem@5 11774 }
philpem@5 11775 if (nx>=0 && nx<dimx()) {
philpem@5 11776 const float w1 = dx*dy, w2 = add?1:(1-w1);
philpem@5 11777 (*this)(nx,ny,z,v) = (T)(w1*val + w2*(*this)(nx,ny,z,v));
philpem@5 11778 }
philpem@5 11779 }
philpem@5 11780 }
philpem@5 11781 return *this;
philpem@5 11782 }
philpem@5 11783
philpem@5 11784 //! Return a reference to the minimum pixel value of the instance image
philpem@5 11785 const T& min() const {
philpem@5 11786 if (is_empty())
philpem@5 11787 throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
philpem@5 11788 pixel_type());
philpem@5 11789 const T *ptrmin = data;
philpem@5 11790 T min_value = *ptrmin;
philpem@5 11791 cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
philpem@5 11792 return *ptrmin;
philpem@5 11793 }
philpem@5 11794
philpem@5 11795 //! Return a reference to the minimum pixel value of the instance image
philpem@5 11796 T& min() {
philpem@5 11797 if (is_empty())
philpem@5 11798 throw CImgInstanceException("CImg<%s>::min() : Instance image is empty.",
philpem@5 11799 pixel_type());
philpem@5 11800 T *ptrmin = data;
philpem@5 11801 T min_value = *ptrmin;
philpem@5 11802 cimg_for(*this,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
philpem@5 11803 return *ptrmin;
philpem@5 11804 }
philpem@5 11805
philpem@5 11806 //! Return a reference to the maximum pixel value of the instance image
philpem@5 11807 const T& max() const {
philpem@5 11808 if (is_empty())
philpem@5 11809 throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
philpem@5 11810 pixel_type());
philpem@5 11811 const T *ptrmax = data;
philpem@5 11812 T max_value = *ptrmax;
philpem@5 11813 cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
philpem@5 11814 return *ptrmax;
philpem@5 11815 }
philpem@5 11816
philpem@5 11817 //! Return a reference to the maximum pixel value of the instance image
philpem@5 11818 T& max() {
philpem@5 11819 if (is_empty())
philpem@5 11820 throw CImgInstanceException("CImg<%s>::max() : Instance image is empty.",
philpem@5 11821 pixel_type());
philpem@5 11822 T *ptrmax = data;
philpem@5 11823 T max_value = *ptrmax;
philpem@5 11824 cimg_for(*this,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
philpem@5 11825 return *ptrmax;
philpem@5 11826 }
philpem@5 11827
philpem@5 11828 //! Return a reference to the minimum pixel value and return also the maximum pixel value.
philpem@5 11829 template<typename t>
philpem@5 11830 const T& minmax(t& max_val) const {
philpem@5 11831 if (is_empty())
philpem@5 11832 throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
philpem@5 11833 pixel_type());
philpem@5 11834 const T *ptrmin = data;
philpem@5 11835 T min_value = *ptrmin, max_value = min_value;
philpem@5 11836 cimg_for(*this,ptr,T) {
philpem@5 11837 const T val = *ptr;
philpem@5 11838 if (val<min_value) { min_value = val; ptrmin = ptr; }
philpem@5 11839 if (val>max_value) max_value = val;
philpem@5 11840 }
philpem@5 11841 max_val = (t)max_value;
philpem@5 11842 return *ptrmin;
philpem@5 11843 }
philpem@5 11844
philpem@5 11845 //! Return a reference to the minimum pixel value and return also the maximum pixel value.
philpem@5 11846 template<typename t>
philpem@5 11847 T& minmax(t& max_val) {
philpem@5 11848 if (is_empty())
philpem@5 11849 throw CImgInstanceException("CImg<%s>::minmax() : Instance image is empty.",
philpem@5 11850 pixel_type());
philpem@5 11851 T *ptrmin = data;
philpem@5 11852 T min_value = *ptrmin, max_value = min_value;
philpem@5 11853 cimg_for(*this,ptr,T) {
philpem@5 11854 const T val = *ptr;
philpem@5 11855 if (val<min_value) { min_value = val; ptrmin = ptr; }
philpem@5 11856 if (val>max_value) max_value = val;
philpem@5 11857 }
philpem@5 11858 max_val = (t)max_value;
philpem@5 11859 return *ptrmin;
philpem@5 11860 }
philpem@5 11861
philpem@5 11862 //! Return a reference to the maximum pixel value and return also the minimum pixel value.
philpem@5 11863 template<typename t>
philpem@5 11864 const T& maxmin(t& min_val) const {
philpem@5 11865 if (is_empty())
philpem@5 11866 throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
philpem@5 11867 pixel_type());
philpem@5 11868 const T *ptrmax = data;
philpem@5 11869 T max_value = *ptrmax, min_value = max_value;
philpem@5 11870 cimg_for(*this,ptr,T) {
philpem@5 11871 const T val = *ptr;
philpem@5 11872 if (val>max_value) { max_value = val; ptrmax = ptr; }
philpem@5 11873 if (val<min_value) min_value = val;
philpem@5 11874 }
philpem@5 11875 min_val = (t)min_value;
philpem@5 11876 return *ptrmax;
philpem@5 11877 }
philpem@5 11878
philpem@5 11879 //! Return a reference to the maximum pixel value and return also the minimum pixel value.
philpem@5 11880 template<typename t>
philpem@5 11881 T& maxmin(t& min_val) {
philpem@5 11882 if (is_empty())
philpem@5 11883 throw CImgInstanceException("CImg<%s>::maxmin() : Instance image is empty.",
philpem@5 11884 pixel_type());
philpem@5 11885 T *ptrmax = data;
philpem@5 11886 T max_value = *ptrmax, min_value = max_value;
philpem@5 11887 cimg_for(*this,ptr,T) {
philpem@5 11888 const T val = *ptr;
philpem@5 11889 if (val>max_value) { max_value = val; ptrmax = ptr; }
philpem@5 11890 if (val<min_value) min_value = val;
philpem@5 11891 }
philpem@5 11892 min_val = (t)min_value;
philpem@5 11893 return *ptrmax;
philpem@5 11894 }
philpem@5 11895
philpem@5 11896 //! Return the sum of all the pixel values in an image.
philpem@5 11897 Tfloat sum() const {
philpem@5 11898 if (is_empty())
philpem@5 11899 throw CImgInstanceException("CImg<%s>::sum() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 11900 pixel_type(),width,height,depth,dim,data);
philpem@5 11901 Tfloat res = 0;
philpem@5 11902 cimg_for(*this,ptr,T) res+=*ptr;
philpem@5 11903 return res;
philpem@5 11904 }
philpem@5 11905
philpem@5 11906 //! Return the mean pixel value of the instance image.
philpem@5 11907 Tfloat mean() const {
philpem@5 11908 if (is_empty())
philpem@5 11909 throw CImgInstanceException("CImg<%s>::mean() : Instance image is empty.",
philpem@5 11910 pixel_type());
philpem@5 11911 Tfloat val = 0;
philpem@5 11912 cimg_for(*this,ptr,T) val+=*ptr;
philpem@5 11913 return val/size();
philpem@5 11914 }
philpem@5 11915
philpem@5 11916 //! Return the variance of the image.
philpem@5 11917 /**
philpem@5 11918 @param variance_method Determines how to calculate the variance
philpem@5 11919 <table border="0">
philpem@5 11920 <tr><td>0</td>
philpem@5 11921 <td>Second moment:
philpem@5 11922 @f$ v = 1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2
philpem@5 11923 = 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right) @f$
philpem@5 11924 with @f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$</td></tr>
philpem@5 11925 <tr><td>1</td>
philpem@5 11926 <td>Best unbiased estimator: @f$ v = \frac{1}{N-1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 @f$</td></tr>
philpem@5 11927 <tr><td>2</td>
philpem@5 11928 <td>Least median of squares</td></tr>
philpem@5 11929 <tr><td>3</td>
philpem@5 11930 <td>Least trimmed of squares</td></tr>
philpem@5 11931 </table>
philpem@5 11932 */
philpem@5 11933 Tfloat variance(const unsigned int variance_method=1) const {
philpem@5 11934 Tfloat foo;
philpem@5 11935 return variancemean(variance_method,foo);
philpem@5 11936 }
philpem@5 11937
philpem@5 11938 //! Return the variance and the mean of the image.
philpem@5 11939 template<typename t>
philpem@5 11940 Tfloat variancemean(const unsigned int variance_method, t& mean) const {
philpem@5 11941 if (is_empty())
philpem@5 11942 throw CImgInstanceException("CImg<%s>::variance() : Instance image is empty.",
philpem@5 11943 pixel_type());
philpem@5 11944 Tfloat variance = 0, average = 0;
philpem@5 11945 const unsigned int siz = size();
philpem@5 11946 switch (variance_method) {
philpem@5 11947 case 3 : { // Least trimmed of Squares
philpem@5 11948 CImg<Tfloat> buf(*this);
philpem@5 11949 const unsigned int siz2 = siz>>1;
philpem@5 11950 { cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; (*ptrs)*=val; average+=val; }}
philpem@5 11951 buf.sort();
philpem@5 11952 Tfloat a = 0;
philpem@5 11953 const Tfloat *ptrs = buf.ptr();
philpem@5 11954 for (unsigned int j = 0; j<siz2; ++j) a+=*(ptrs++);
philpem@5 11955 const Tfloat sig = (Tfloat)(2.6477*cimg_std::sqrt(a/siz2));
philpem@5 11956 variance = sig*sig;
philpem@5 11957 } break;
philpem@5 11958 case 2 : { // Least Median of Squares (MAD)
philpem@5 11959 CImg<Tfloat> buf(*this);
philpem@5 11960 buf.sort();
philpem@5 11961 const unsigned int siz2 = siz>>1;
philpem@5 11962 const Tfloat med_i = buf[siz2];
philpem@5 11963 cimg_for(buf,ptrs,Tfloat) { const Tfloat val = *ptrs; *ptrs = cimg::abs(val - med_i); average+=val; }
philpem@5 11964 buf.sort();
philpem@5 11965 const Tfloat sig = (Tfloat)(1.4828*buf[siz2]);
philpem@5 11966 variance = sig*sig;
philpem@5 11967 } break;
philpem@5 11968 case 1 : { // Least mean square (robust definition)
philpem@5 11969 Tfloat S = 0, S2 = 0;
philpem@5 11970 cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
philpem@5 11971 variance = siz>1?(S2 - S*S/siz)/(siz - 1):0;
philpem@5 11972 average = S;
philpem@5 11973 } break;
philpem@5 11974 case 0 :{ // Least mean square (standard definition)
philpem@5 11975 Tfloat S = 0, S2 = 0;
philpem@5 11976 cimg_for(*this,ptr,T) { const Tfloat val = (Tfloat)*ptr; S+=val; S2+=val*val; }
philpem@5 11977 variance = (S2 - S*S/siz)/siz;
philpem@5 11978 average = S;
philpem@5 11979 } break;
philpem@5 11980 default :
philpem@5 11981 throw CImgArgumentException("CImg<%s>::variancemean() : Incorrect parameter 'variance_method = %d' (correct values are 0,1,2 or 3).",
philpem@5 11982 pixel_type(),variance_method);
philpem@5 11983 }
philpem@5 11984 mean = (t)(average/siz);
philpem@5 11985 return variance>0?variance:0;
philpem@5 11986 }
philpem@5 11987
philpem@5 11988 //! Return the kth smallest element of the image.
philpem@5 11989 // (Adapted from the numerical recipies for CImg)
philpem@5 11990 T kth_smallest(const unsigned int k) const {
philpem@5 11991 if (is_empty())
philpem@5 11992 throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 11993 pixel_type(),width,height,depth,dim,data);
philpem@5 11994 CImg<T> arr(*this);
philpem@5 11995 unsigned long l = 0, ir = size()-1;
philpem@5 11996 for (;;) {
philpem@5 11997 if (ir<=l+1) {
philpem@5 11998 if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]);
philpem@5 11999 return arr[k];
philpem@5 12000 } else {
philpem@5 12001 const unsigned long mid = (l+ir)>>1;
philpem@5 12002 cimg::swap(arr[mid],arr[l+1]);
philpem@5 12003 if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]);
philpem@5 12004 if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]);
philpem@5 12005 if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]);
philpem@5 12006 unsigned long i = l+1, j = ir;
philpem@5 12007 const T pivot = arr[l+1];
philpem@5 12008 for (;;) {
philpem@5 12009 do ++i; while (arr[i]<pivot);
philpem@5 12010 do --j; while (arr[j]>pivot);
philpem@5 12011 if (j<i) break;
philpem@5 12012 cimg::swap(arr[i],arr[j]);
philpem@5 12013 }
philpem@5 12014 arr[l+1] = arr[j];
philpem@5 12015 arr[j] = pivot;
philpem@5 12016 if (j>=k) ir=j-1;
philpem@5 12017 if (j<=k) l=i;
philpem@5 12018 }
philpem@5 12019 }
philpem@5 12020 return 0;
philpem@5 12021 }
philpem@5 12022
philpem@5 12023 //! Compute a statistics vector (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
philpem@5 12024 CImg<T>& stats(const unsigned int variance_method=1) {
philpem@5 12025 return get_stats(variance_method).transfer_to(*this);
philpem@5 12026 }
philpem@5 12027
philpem@5 12028 CImg<Tfloat> get_stats(const unsigned int variance_method=1) const {
philpem@5 12029 if (is_empty()) return CImg<Tfloat>();
philpem@5 12030 const unsigned long siz = size();
philpem@5 12031 const T *const odata = data;
philpem@5 12032 const T *pm = odata, *pM = odata;
philpem@5 12033 Tfloat S = 0, S2 = 0;
philpem@5 12034 T m = *pm, M = m;
philpem@5 12035 cimg_for(*this,ptr,T) {
philpem@5 12036 const T val = *ptr;
philpem@5 12037 const Tfloat fval = (Tfloat)val;
philpem@5 12038 if (val<m) { m = val; pm = ptr; }
philpem@5 12039 if (val>M) { M = val; pM = ptr; }
philpem@5 12040 S+=fval;
philpem@5 12041 S2+=fval*fval;
philpem@5 12042 }
philpem@5 12043 const Tfloat
philpem@5 12044 mean_value = S/siz,
philpem@5 12045 _variance_value = variance_method==0?(S2 - S*S/siz)/siz:
philpem@5 12046 (variance_method==1?(siz>1?(S2 - S*S/siz)/(siz - 1):0):
philpem@5 12047 variance(variance_method)),
philpem@5 12048 variance_value = _variance_value>0?_variance_value:0;
philpem@5 12049 int
philpem@5 12050 xm = 0, ym = 0, zm = 0, vm = 0,
philpem@5 12051 xM = 0, yM = 0, zM = 0, vM = 0;
philpem@5 12052 contains(*pm,xm,ym,zm,vm);
philpem@5 12053 contains(*pM,xM,yM,zM,vM);
philpem@5 12054 return CImg<Tfloat>(1,12).fill((Tfloat)m,(Tfloat)M,mean_value,variance_value,
philpem@5 12055 (Tfloat)xm,(Tfloat)ym,(Tfloat)zm,(Tfloat)vm,
philpem@5 12056 (Tfloat)xM,(Tfloat)yM,(Tfloat)zM,(Tfloat)vM);
philpem@5 12057 }
philpem@5 12058
philpem@5 12059 //! Return the median value of the image.
philpem@5 12060 T median() const {
philpem@5 12061 const unsigned int s = size();
philpem@5 12062 const T res = kth_smallest(s>>1);
philpem@5 12063 return (s%2)?res:((res+kth_smallest((s>>1)-1))/2);
philpem@5 12064 }
philpem@5 12065
philpem@5 12066 //! Compute the MSE (Mean-Squared Error) between two images.
philpem@5 12067 template<typename t>
philpem@5 12068 Tfloat MSE(const CImg<t>& img) const {
philpem@5 12069 if (img.size()!=size())
philpem@5 12070 throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.",
philpem@5 12071 pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim);
philpem@5 12072
philpem@5 12073 Tfloat vMSE = 0;
philpem@5 12074 const t* ptr2 = img.end();
philpem@5 12075 cimg_for(*this,ptr1,T) {
philpem@5 12076 const Tfloat diff = (Tfloat)*ptr1 - (Tfloat)*(--ptr2);
philpem@5 12077 vMSE += diff*diff;
philpem@5 12078 }
philpem@5 12079 vMSE/=img.size();
philpem@5 12080 return vMSE;
philpem@5 12081 }
philpem@5 12082
philpem@5 12083 //! Compute the PSNR between two images.
philpem@5 12084 template<typename t>
philpem@5 12085 Tfloat PSNR(const CImg<t>& img, const Tfloat valmax=(Tfloat)255) const {
philpem@5 12086 const Tfloat vMSE = (Tfloat)cimg_std::sqrt(MSE(img));
philpem@5 12087 return (vMSE!=0)?(Tfloat)(20*cimg_std::log10(valmax/vMSE)):(Tfloat)(cimg::type<Tfloat>::max());
philpem@5 12088 }
philpem@5 12089
philpem@5 12090 //! Return the trace of the image, viewed as a matrix.
philpem@5 12091 Tfloat trace() const {
philpem@5 12092 if (is_empty())
philpem@5 12093 throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.",
philpem@5 12094 pixel_type(),width,height,depth,dim,data);
philpem@5 12095 Tfloat res = 0;
philpem@5 12096 cimg_forX(*this,k) res+=(*this)(k,k);
philpem@5 12097 return res;
philpem@5 12098 }
philpem@5 12099
philpem@5 12100 //! Return the dot product of the current vector/matrix with the vector/matrix \p img.
philpem@5 12101 template<typename t>
philpem@5 12102 Tfloat dot(const CImg<t>& img) const {
philpem@5 12103 if (is_empty())
philpem@5 12104 throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.",
philpem@5 12105 pixel_type(),width,height,depth,dim,data);
philpem@5 12106 if (!img)
philpem@5 12107 throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.",
philpem@5 12108 pixel_type(),img.width,img.height,img.depth,img.dim,img.data);
philpem@5 12109 const unsigned long nb = cimg::min(size(),img.size());
philpem@5 12110 Tfloat res = 0;
philpem@5 12111 for (unsigned long off = 0; off<nb; ++off) res+=(Tfloat)data[off]*(Tfloat)img[off];
philpem@5 12112 return res;
philpem@5 12113 }
philpem@5 12114
philpem@5 12115 //! Return the determinant of the image, viewed as a matrix.
philpem@5 12116 Tfloat det() const {
philpem@5 12117 if (is_empty() || width!=height || depth!=1 || dim!=1)
philpem@5 12118 throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.",
philpem@5 12119 pixel_type(),width,height,depth,dim,data);
philpem@5 12120 switch (width) {
philpem@5 12121 case 1 : return (Tfloat)((*this)(0,0));
philpem@5 12122 case 2 : return (Tfloat)((*this)(0,0))*(Tfloat)((*this)(1,1)) - (Tfloat)((*this)(0,1))*(Tfloat)((*this)(1,0));
philpem@5 12123 case 3 : {
philpem@5 12124 const Tfloat
philpem@5 12125 a = (Tfloat)data[0], d = (Tfloat)data[1], g = (Tfloat)data[2],
philpem@5 12126 b = (Tfloat)data[3], e = (Tfloat)data[4], h = (Tfloat)data[5],
philpem@5 12127 c = (Tfloat)data[6], f = (Tfloat)data[7], i = (Tfloat)data[8];
philpem@5 12128 return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e;
philpem@5 12129 }
philpem@5 12130 default : {
philpem@5 12131 CImg<Tfloat> lu(*this);
philpem@5 12132 CImg<uintT> indx;
philpem@5 12133 bool d;
philpem@5 12134 lu._LU(indx,d);
philpem@5 12135 Tfloat res = d?(Tfloat)1:(Tfloat)-1;
philpem@5 12136 cimg_forX(lu,i) res*=lu(i,i);
philpem@5 12137 return res;
philpem@5 12138 }
philpem@5 12139 }
philpem@5 12140 return 0;
philpem@5 12141 }
philpem@5 12142
philpem@5 12143 //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf).
philpem@5 12144 Tfloat norm(const int norm_type=2) const {
philpem@5 12145 if (is_empty())
philpem@5 12146 throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.",
philpem@5 12147 pixel_type(),width,height,depth,dim,data);
philpem@5 12148 Tfloat res = 0;
philpem@5 12149 switch (norm_type) {
philpem@5 12150 case -1 : {
philpem@5 12151 cimg_foroff(*this,off) {
philpem@5 12152 const Tfloat tmp = cimg::abs((Tfloat)data[off]);
philpem@5 12153 if (tmp>res) res = tmp;
philpem@5 12154 }
philpem@5 12155 return res;
philpem@5 12156 } break;
philpem@5 12157 case 1 : {
philpem@5 12158 cimg_foroff(*this,off) res+=cimg::abs((Tfloat)data[off]);
philpem@5 12159 return res;
philpem@5 12160 } break;
philpem@5 12161 case 2 : return (Tfloat)cimg_std::sqrt(dot(*this)); break;
philpem@5 12162 default :
philpem@5 12163 throw CImgArgumentException("CImg<%s>::norm() : Incorrect parameter 'norm_type=%d' (correct values are -1,1 or 2).",
philpem@5 12164 pixel_type(),norm_type);
philpem@5 12165 }
philpem@5 12166 return 0;
philpem@5 12167 }
philpem@5 12168
philpem@5 12169 //! Return a C-string containing the values of the instance image.
philpem@5 12170 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
philpem@5 12171 if (is_empty()) return CImg<charT>(1,1,1,1,0);
philpem@5 12172 const unsigned int siz = (unsigned int)size();
philpem@5 12173 CImgList<charT> items;
philpem@5 12174 char item[256] = { 0 };
philpem@5 12175 const T *ptrs = ptr();
philpem@5 12176 for (unsigned int off = 0; off<siz-1; ++off) {
philpem@5 12177 cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*(ptrs++)));
philpem@5 12178 const int l = cimg::strlen(item);
philpem@5 12179 items.insert(CImg<charT>(item,l+1));
philpem@5 12180 items[items.size-1](l) = separator;
philpem@5 12181 }
philpem@5 12182 cimg_std::sprintf(item,cimg::type<T>::format(),cimg::type<T>::format(*ptrs));
philpem@5 12183 items.insert(CImg<charT>(item,cimg::strlen(item)+1));
philpem@5 12184 CImg<ucharT> res = items.get_append('x');
philpem@5 12185 if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
philpem@5 12186 return res;
philpem@5 12187 }
philpem@5 12188
philpem@5 12189 //! Display informations about the image on the standard error output.
philpem@5 12190 /**
philpem@5 12191 \param title Name for the considered image (optional).
philpem@5 12192 \param display_stats Compute and display image statistics (optional).
philpem@5 12193 **/
philpem@5 12194 const CImg<T>& print(const char *title=0, const bool display_stats=true) const {
philpem@5 12195 int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
philpem@5 12196 static CImg<doubleT> st;
philpem@5 12197 if (!is_empty() && display_stats) {
philpem@5 12198 st = get_stats();
philpem@5 12199 xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
philpem@5 12200 xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
philpem@5 12201 }
philpem@5 12202 const unsigned long siz = size(), msiz = siz*sizeof(T), siz1 = siz-1;
philpem@5 12203 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2), width1 = width-1;
philpem@5 12204 char ntitle[64] = { 0 };
philpem@5 12205 if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
philpem@5 12206 cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = (%u,%u,%u,%u) [%lu %s], data = (%s*)%p (%s) = [ ",
philpem@5 12207 title?title:ntitle,(void*)this,width,height,depth,dim,
philpem@5 12208 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
philpem@5 12209 mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
philpem@5 12210 pixel_type(),(void*)data,is_shared?"shared":"not shared");
philpem@5 12211 if (!is_empty()) cimg_foroff(*this,off) {
philpem@5 12212 cimg_std::fprintf(cimg_stdout,cimg::type<T>::format(),cimg::type<T>::format(data[off]));
philpem@5 12213 if (off!=siz1) cimg_std::fprintf(cimg_stdout,"%s",off%width==width1?" ; ":" ");
philpem@5 12214 if (off==7 && siz>16) { off = siz1-8; if (off!=7) cimg_std::fprintf(cimg_stdout,"... "); }
philpem@5 12215 }
philpem@5 12216 if (!is_empty() && display_stats)
philpem@5 12217 cimg_std::fprintf(cimg_stdout," ], min = %g, max = %g, mean = %g, std = %g, coords(min) = (%u,%u,%u,%u), coords(max) = (%u,%u,%u,%u).\n",
philpem@5 12218 st[0],st[1],st[2],cimg_std::sqrt(st[3]),xm,ym,zm,vm,xM,yM,zM,vM);
philpem@5 12219 else cimg_std::fprintf(cimg_stdout,"%s].\n",is_empty()?"":" ");
philpem@5 12220 return *this;
philpem@5 12221 }
philpem@5 12222
philpem@5 12223 //@}
philpem@5 12224 //------------------------------------------
philpem@5 12225 //
philpem@5 12226 //! \name Arithmetic and Boolean Operators
philpem@5 12227 //@{
philpem@5 12228 //------------------------------------------
philpem@5 12229
philpem@5 12230 //! Assignment operator.
philpem@5 12231 /**
philpem@5 12232 This operator assigns a copy of the input image \p img to the current instance image.
philpem@5 12233 \param img The input image to copy.
philpem@5 12234 \remark
philpem@5 12235 - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties.
philpem@5 12236 **/
philpem@5 12237 template<typename t>
philpem@5 12238 CImg<T>& operator=(const CImg<t>& img) {
philpem@5 12239 return assign(img);
philpem@5 12240 }
philpem@5 12241
philpem@5 12242 CImg<T>& operator=(const CImg<T>& img) {
philpem@5 12243 return assign(img);
philpem@5 12244 }
philpem@5 12245
philpem@5 12246 //! Assign values of a C-array to the instance image.
philpem@5 12247 /**
philpem@5 12248 \param buf Pointer to a C-style array having a size of (at least) <tt>this->size()</tt>.
philpem@5 12249
philpem@5 12250 - Replace pixel values by the content of the array \c buf.
philpem@5 12251 - Warning : the value types in the array and in the image must be the same.
philpem@5 12252
philpem@5 12253 \par example:
philpem@5 12254 \code
philpem@5 12255 float tab[4*4] = { 1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16 }; // Define a 4x4 matrix in C-style.
philpem@5 12256 CImg<float> matrice(4,4); // Define a 4x4 greyscale image.
philpem@5 12257 matrice = tab; // Fill the image by the values in tab.
philpem@5 12258 \endcode
philpem@5 12259 **/
philpem@5 12260 CImg<T>& operator=(const T *buf) {
philpem@5 12261 return assign(buf,width,height,depth,dim);
philpem@5 12262 }
philpem@5 12263
philpem@5 12264 //! Assign a value to each image pixel of the instance image.
philpem@5 12265 CImg<T>& operator=(const T val) {
philpem@5 12266 return fill(val);
philpem@5 12267 }
philpem@5 12268
philpem@5 12269 //! Operator+
philpem@5 12270 /**
philpem@5 12271 \remark
philpem@5 12272 - This operator can be used to get a non-shared copy of an image.
philpem@5 12273 **/
philpem@5 12274 CImg<T> operator+() const {
philpem@5 12275 return CImg<T>(*this,false);
philpem@5 12276 }
philpem@5 12277
philpem@5 12278 //! Operator+=;
philpem@5 12279 #ifdef cimg_use_visualcpp6
philpem@5 12280 CImg<T>& operator+=(const T val)
philpem@5 12281 #else
philpem@5 12282 template<typename t>
philpem@5 12283 CImg<T>& operator+=(const t val)
philpem@5 12284 #endif
philpem@5 12285 {
philpem@5 12286 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)+val);
philpem@5 12287 return *this;
philpem@5 12288 }
philpem@5 12289
philpem@5 12290 //! Operator+=
philpem@5 12291 template<typename t>
philpem@5 12292 CImg<T>& operator+=(const CImg<t>& img) {
philpem@5 12293 if (is_overlapped(img)) return *this+=+img;
philpem@5 12294 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12295 t *ptrs = img.data + smin;
philpem@5 12296 for (T *ptrd = data + smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))) {}
philpem@5 12297 return *this;
philpem@5 12298 }
philpem@5 12299
philpem@5 12300 //! Operator++ (prefix)
philpem@5 12301 CImg<T>& operator++() {
philpem@5 12302 cimg_for(*this,ptr,T) ++(*ptr);
philpem@5 12303 return *this;
philpem@5 12304 }
philpem@5 12305
philpem@5 12306 //! Operator++ (postfix)
philpem@5 12307 CImg<T> operator++(int) {
philpem@5 12308 const CImg<T> copy(*this,false);
philpem@5 12309 ++*this;
philpem@5 12310 return copy;
philpem@5 12311 }
philpem@5 12312
philpem@5 12313 //! Operator-.
philpem@5 12314 CImg<T> operator-() const {
philpem@5 12315 return CImg<T>(width,height,depth,dim,0)-=*this;
philpem@5 12316 }
philpem@5 12317
philpem@5 12318 //! Operator-=.
philpem@5 12319 #ifdef cimg_use_visualcpp6
philpem@5 12320 CImg<T>& operator-=(const T val)
philpem@5 12321 #else
philpem@5 12322 template<typename t>
philpem@5 12323 CImg<T>& operator-=(const t val)
philpem@5 12324 #endif
philpem@5 12325 {
philpem@5 12326 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)-val);
philpem@5 12327 return *this;
philpem@5 12328 }
philpem@5 12329
philpem@5 12330 //! Operator-=.
philpem@5 12331 template<typename t>
philpem@5 12332 CImg<T>& operator-=(const CImg<t>& img) {
philpem@5 12333 if (is_overlapped(img)) return *this-=+img;
philpem@5 12334 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12335 t *ptrs = img.data+smin;
philpem@5 12336 for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd) = (T)((*ptrd)-(*(--ptrs)))) {}
philpem@5 12337 return *this;
philpem@5 12338 }
philpem@5 12339
philpem@5 12340 //! Operator-- (prefix).
philpem@5 12341 CImg<T>& operator--() {
philpem@5 12342 cimg_for(*this,ptr,T) *ptr = *ptr-(T)1;
philpem@5 12343 return *this;
philpem@5 12344 }
philpem@5 12345
philpem@5 12346 //! Operator-- (postfix).
philpem@5 12347 CImg<T> operator--(int) {
philpem@5 12348 CImg<T> copy(*this,false);
philpem@5 12349 --*this;
philpem@5 12350 return copy;
philpem@5 12351 }
philpem@5 12352
philpem@5 12353 //! Operator*=.
philpem@5 12354 #ifdef cimg_use_visualcpp6
philpem@5 12355 CImg<T>& operator*=(const double val)
philpem@5 12356 #else
philpem@5 12357 template<typename t>
philpem@5 12358 CImg<T>& operator*=(const t val)
philpem@5 12359 #endif
philpem@5 12360 {
philpem@5 12361 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)*val);
philpem@5 12362 return *this;
philpem@5 12363 }
philpem@5 12364
philpem@5 12365 //! Operator*=.
philpem@5 12366 template<typename t>
philpem@5 12367 CImg<T>& operator*=(const CImg<t>& img) {
philpem@5 12368 return ((*this)*img).transfer_to(*this);
philpem@5 12369 }
philpem@5 12370
philpem@5 12371 //! Operator/=.
philpem@5 12372 #ifdef cimg_use_visualcpp6
philpem@5 12373 CImg<T>& operator/=(const double val)
philpem@5 12374 #else
philpem@5 12375 template<typename t>
philpem@5 12376 CImg<T>& operator/=(const t val)
philpem@5 12377 #endif
philpem@5 12378 {
philpem@5 12379 cimg_for(*this,ptr,T) (*ptr) = (T)((*ptr)/val);
philpem@5 12380 return *this;
philpem@5 12381 }
philpem@5 12382
philpem@5 12383 //! Operator/=.
philpem@5 12384 template<typename t>
philpem@5 12385 CImg<T>& operator/=(const CImg<t>& img) {
philpem@5 12386 return assign(*this*img.get_invert());
philpem@5 12387 }
philpem@5 12388
philpem@5 12389 //! Modulo.
philpem@5 12390 template<typename t>
philpem@5 12391 CImg<typename cimg::superset<T,t>::type> operator%(const CImg<t>& img) const {
philpem@5 12392 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12393 return CImg<Tt>(*this,false)%=img;
philpem@5 12394 }
philpem@5 12395
philpem@5 12396 //! Modulo.
philpem@5 12397 CImg<T> operator%(const T val) const {
philpem@5 12398 return (+*this)%=val;
philpem@5 12399 }
philpem@5 12400
philpem@5 12401 //! In-place modulo.
philpem@5 12402 CImg<T>& operator%=(const T val) {
philpem@5 12403 cimg_for(*this,ptr,T) (*ptr) = (T)cimg::mod(*ptr,val);
philpem@5 12404 return *this;
philpem@5 12405 }
philpem@5 12406
philpem@5 12407 //! In-place modulo.
philpem@5 12408 template<typename t>
philpem@5 12409 CImg<T>& operator%=(const CImg<t>& img) {
philpem@5 12410 if (is_overlapped(img)) return *this%=+img;
philpem@5 12411 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12412 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12413 const t *ptrs = img.data + smin;
philpem@5 12414 for (T *ptrd = data + smin; ptrd>data; ) {
philpem@5 12415 T& val = *(--ptrd);
philpem@5 12416 val = (T)cimg::mod((Tt)val,(Tt)*(--ptrs));
philpem@5 12417 }
philpem@5 12418 return *this;
philpem@5 12419 }
philpem@5 12420
philpem@5 12421 //! Bitwise AND.
philpem@5 12422 template<typename t>
philpem@5 12423 CImg<typename cimg::superset<T,t>::type> operator&(const CImg<t>& img) const {
philpem@5 12424 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12425 return CImg<Tt>(*this,false)&=img;
philpem@5 12426 }
philpem@5 12427
philpem@5 12428 //! Bitwise AND.
philpem@5 12429 CImg<T> operator&(const T val) const {
philpem@5 12430 return (+*this)&=val;
philpem@5 12431 }
philpem@5 12432
philpem@5 12433 //! In-place bitwise AND.
philpem@5 12434 template<typename t>
philpem@5 12435 CImg<T>& operator&=(const CImg<t>& img) {
philpem@5 12436 if (is_overlapped(img)) return *this&=+img;
philpem@5 12437 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12438 const t *ptrs = img.data + smin;
philpem@5 12439 for (T *ptrd = data + smin; ptrd>data; ) {
philpem@5 12440 T& val = *(--ptrd);
philpem@5 12441 val = (T)((unsigned long)val & (unsigned long)*(--ptrs));
philpem@5 12442 }
philpem@5 12443 return *this;
philpem@5 12444 }
philpem@5 12445
philpem@5 12446 //! In-place bitwise AND.
philpem@5 12447 CImg<T>& operator&=(const T val) {
philpem@5 12448 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr & (unsigned long)val);
philpem@5 12449 return *this;
philpem@5 12450 }
philpem@5 12451
philpem@5 12452 //! Bitwise OR.
philpem@5 12453 template<typename t>
philpem@5 12454 CImg<typename cimg::superset<T,t>::type> operator|(const CImg<t>& img) const {
philpem@5 12455 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12456 return CImg<Tt>(*this,false)|=img;
philpem@5 12457 }
philpem@5 12458
philpem@5 12459 //! Bitwise OR.
philpem@5 12460 CImg<T> operator|(const T val) const {
philpem@5 12461 return (+*this)|=val;
philpem@5 12462 }
philpem@5 12463
philpem@5 12464 //! In-place bitwise OR.
philpem@5 12465 template<typename t>
philpem@5 12466 CImg<T>& operator|=(const CImg<t>& img) {
philpem@5 12467 if (is_overlapped(img)) return *this|=+img;
philpem@5 12468 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12469 const t *ptrs = img.data + smin;
philpem@5 12470 for (T *ptrd = data + smin; ptrd>data; ) {
philpem@5 12471 T& val = *(--ptrd);
philpem@5 12472 val = (T)((unsigned long)val | (unsigned long)*(--ptrs));
philpem@5 12473 }
philpem@5 12474 return *this;
philpem@5 12475 }
philpem@5 12476
philpem@5 12477 //! In-place bitwise OR.
philpem@5 12478 CImg<T>& operator|=(const T val) {
philpem@5 12479 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr | (unsigned long)val);
philpem@5 12480 return *this;
philpem@5 12481 }
philpem@5 12482
philpem@5 12483 //! Bitwise XOR.
philpem@5 12484 template<typename t>
philpem@5 12485 CImg<typename cimg::superset<T,t>::type> operator^(const CImg<t>& img) const {
philpem@5 12486 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12487 return CImg<Tt>(*this,false)^=img;
philpem@5 12488 }
philpem@5 12489
philpem@5 12490 //! Bitwise XOR.
philpem@5 12491 CImg<T> operator^(const T val) const {
philpem@5 12492 return (+*this)^=val;
philpem@5 12493 }
philpem@5 12494
philpem@5 12495 //! In-place bitwise XOR.
philpem@5 12496 template<typename t>
philpem@5 12497 CImg<T>& operator^=(const CImg<t>& img) {
philpem@5 12498 if (is_overlapped(img)) return *this^=+img;
philpem@5 12499 const unsigned int smin = cimg::min(size(),img.size());
philpem@5 12500 const t *ptrs = img.data + smin;
philpem@5 12501 for (T *ptrd = data+smin; ptrd>data; ) {
philpem@5 12502 T& val = *(--ptrd);
philpem@5 12503 val =(T)((unsigned long)val ^ (unsigned long)*(--ptrs));
philpem@5 12504 }
philpem@5 12505 return *this;
philpem@5 12506 }
philpem@5 12507
philpem@5 12508 //! In-place bitwise XOR.
philpem@5 12509 CImg<T>& operator^=(const T val) {
philpem@5 12510 cimg_for(*this,ptr,T) *ptr = (T)((unsigned long)*ptr ^ (unsigned long)val);
philpem@5 12511 return *this;
philpem@5 12512 }
philpem@5 12513
philpem@5 12514 //! Bitwise NOT.
philpem@5 12515 CImg<T> operator~() const {
philpem@5 12516 CImg<T> res(width,height,depth,dim);
philpem@5 12517 const T *ptrs = end();
philpem@5 12518 cimg_for(res,ptrd,T) { const unsigned long val = (unsigned long)*(--ptrs); *ptrd = (T)~val; }
philpem@5 12519 return res;
philpem@5 12520 }
philpem@5 12521
philpem@5 12522 //! Bitwise left shift.
philpem@5 12523 CImg<T>& operator<<=(const int n) {
philpem@5 12524 cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<<n);
philpem@5 12525 return *this;
philpem@5 12526 }
philpem@5 12527
philpem@5 12528 //! Bitwise left shift.
philpem@5 12529 CImg<T> operator<<(const int n) const {
philpem@5 12530 return (+*this)<<=n;
philpem@5 12531 }
philpem@5 12532
philpem@5 12533 //! Bitwise right shift.
philpem@5 12534 CImg<T>& operator>>=(const int n) {
philpem@5 12535 cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n);
philpem@5 12536 return *this;
philpem@5 12537 }
philpem@5 12538
philpem@5 12539 //! Bitwise right shift.
philpem@5 12540 CImg<T> operator>>(const int n) const {
philpem@5 12541 return (+*this)>>=n;
philpem@5 12542 }
philpem@5 12543
philpem@5 12544 //! Boolean equality.
philpem@5 12545 template<typename t>
philpem@5 12546 bool operator==(const CImg<t>& img) const {
philpem@5 12547 const unsigned int siz = size();
philpem@5 12548 bool vequal = true;
philpem@5 12549 if (siz!=img.size()) return false;
philpem@5 12550 t *ptrs = img.data + siz;
philpem@5 12551 for (T *ptrd = data + siz; vequal && ptrd>data; vequal = vequal && ((*(--ptrd))==(*(--ptrs)))) {}
philpem@5 12552 return vequal;
philpem@5 12553 }
philpem@5 12554
philpem@5 12555 //! Boolean difference.
philpem@5 12556 template<typename t>
philpem@5 12557 bool operator!=(const CImg<t>& img) const {
philpem@5 12558 return !((*this)==img);
philpem@5 12559 }
philpem@5 12560
philpem@5 12561 //! Return a list of two images { *this, img }.
philpem@5 12562 template<typename t>
philpem@5 12563 CImgList<typename cimg::superset<T,t>::type> operator<<(const CImg<t>& img) const {
philpem@5 12564 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12565 return CImgList<Tt>(*this,img);
philpem@5 12566 }
philpem@5 12567
philpem@5 12568 //! Return a copy of \p list, where image *this has been inserted at first position.
philpem@5 12569 template<typename t>
philpem@5 12570 CImgList<typename cimg::superset<T,t>::type> operator<<(const CImgList<t>& list) const {
philpem@5 12571 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12572 return CImgList<Tt>(list).insert(*this,0);
philpem@5 12573 }
philpem@5 12574
philpem@5 12575 //! Return a list of two images { *this, img }.
philpem@5 12576 template<typename t>
philpem@5 12577 CImgList<typename cimg::superset<T,t>::type> operator>>(const CImg<t>& img) const {
philpem@5 12578 return (*this)<<img;
philpem@5 12579 }
philpem@5 12580
philpem@5 12581 //! Insert an image into the begining of an image list.
philpem@5 12582 template<typename t>
philpem@5 12583 CImgList<t>& operator>>(const CImgList<t>& list) const {
philpem@5 12584 return list.insert(*this,0);
philpem@5 12585 }
philpem@5 12586
philpem@5 12587 //! Display an image into a CImgDisplay.
philpem@5 12588 const CImg<T>& operator>>(CImgDisplay& disp) const {
philpem@5 12589 return display(disp);
philpem@5 12590 }
philpem@5 12591
philpem@5 12592 //@}
philpem@5 12593 //---------------------------------------
philpem@5 12594 //
philpem@5 12595 //! \name Usual Mathematics Functions
philpem@5 12596 //@{
philpem@5 12597 //---------------------------------------
philpem@5 12598
philpem@5 12599 //! Apply a R->R function on all pixel values.
philpem@5 12600 template<typename t>
philpem@5 12601 CImg<T>& apply(t& func) {
philpem@5 12602 cimg_for(*this,ptr,T) *ptr = func(*ptr);
philpem@5 12603 return *this;
philpem@5 12604 }
philpem@5 12605
philpem@5 12606 template<typename t>
philpem@5 12607 CImg<T> get_apply(t& func) const {
philpem@5 12608 return (+*this).apply(func);
philpem@5 12609 }
philpem@5 12610
philpem@5 12611 //! Pointwise multiplication between two images.
philpem@5 12612 template<typename t>
philpem@5 12613 CImg<T>& mul(const CImg<t>& img) {
philpem@5 12614 if (is_overlapped(img)) return mul(+img);
philpem@5 12615 t *ptrs = img.data;
philpem@5 12616 T *ptrf = data + cimg::min(size(),img.size());
philpem@5 12617 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd*(*(ptrs++)));
philpem@5 12618 return *this;
philpem@5 12619 }
philpem@5 12620
philpem@5 12621 template<typename t>
philpem@5 12622 CImg<typename cimg::superset<T,t>::type> get_mul(const CImg<t>& img) const {
philpem@5 12623 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12624 return CImg<Tt>(*this,false).mul(img);
philpem@5 12625 }
philpem@5 12626
philpem@5 12627 //! Pointwise division between two images.
philpem@5 12628 template<typename t>
philpem@5 12629 CImg<T>& div(const CImg<t>& img) {
philpem@5 12630 if (is_overlapped(img)) return div(+img);
philpem@5 12631 t *ptrs = img.data;
philpem@5 12632 T *ptrf = data + cimg::min(size(),img.size());
philpem@5 12633 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)(*ptrd/(*(ptrs++)));
philpem@5 12634 return *this;
philpem@5 12635 }
philpem@5 12636
philpem@5 12637 template<typename t>
philpem@5 12638 CImg<typename cimg::superset<T,t>::type> get_div(const CImg<t>& img) const {
philpem@5 12639 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12640 return CImg<Tt>(*this,false).div(img);
philpem@5 12641 }
philpem@5 12642
philpem@5 12643 //! Pointwise max operator between two images.
philpem@5 12644 template<typename t>
philpem@5 12645 CImg<T>& max(const CImg<t>& img) {
philpem@5 12646 if (is_overlapped(img)) return max(+img);
philpem@5 12647 t *ptrs = img.data;
philpem@5 12648 T *ptrf = data + cimg::min(size(),img.size());
philpem@5 12649 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::max((T)*(ptrs++),*ptrd);
philpem@5 12650 return *this;
philpem@5 12651 }
philpem@5 12652
philpem@5 12653 template<typename t>
philpem@5 12654 CImg<typename cimg::superset<T,t>::type> get_max(const CImg<t>& img) const {
philpem@5 12655 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12656 return CImg<Tt>(*this,false).max(img);
philpem@5 12657 }
philpem@5 12658
philpem@5 12659 //! Pointwise max operator between an image and a value.
philpem@5 12660 CImg<T>& max(const T val) {
philpem@5 12661 cimg_for(*this,ptr,T) (*ptr) = cimg::max(*ptr,val);
philpem@5 12662 return *this;
philpem@5 12663 }
philpem@5 12664
philpem@5 12665 CImg<T> get_max(const T val) const {
philpem@5 12666 return (+*this).max(val);
philpem@5 12667 }
philpem@5 12668
philpem@5 12669 //! Pointwise min operator between two images.
philpem@5 12670 template<typename t>
philpem@5 12671 CImg<T>& min(const CImg<t>& img) {
philpem@5 12672 if (is_overlapped(img)) return min(+img);
philpem@5 12673 t *ptrs = img.data;
philpem@5 12674 T *ptrf = data + cimg::min(size(),img.size());
philpem@5 12675 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = cimg::min((T)*(ptrs++),*ptrd);
philpem@5 12676 return *this;
philpem@5 12677 }
philpem@5 12678
philpem@5 12679 template<typename t>
philpem@5 12680 CImg<typename cimg::superset<T,t>::type> get_min(const CImg<t>& img) const {
philpem@5 12681 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 12682 return CImg<Tt>(*this,false).min(img);
philpem@5 12683 }
philpem@5 12684
philpem@5 12685 //! Pointwise min operator between an image and a value.
philpem@5 12686 CImg<T>& min(const T val) {
philpem@5 12687 cimg_for(*this,ptr,T) (*ptr) = cimg::min(*ptr,val);
philpem@5 12688 return *this;
philpem@5 12689 }
philpem@5 12690
philpem@5 12691 CImg<T> get_min(const T val) const {
philpem@5 12692 return (+*this).min(val);
philpem@5 12693 }
philpem@5 12694
philpem@5 12695 //! Compute the square value of each pixel.
philpem@5 12696 CImg<T>& sqr() {
philpem@5 12697 cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)(val*val); };
philpem@5 12698 return *this;
philpem@5 12699 }
philpem@5 12700
philpem@5 12701 CImg<Tfloat> get_sqr() const {
philpem@5 12702 return CImg<Tfloat>(*this,false).sqr();
philpem@5 12703 }
philpem@5 12704
philpem@5 12705 //! Compute the square root of each pixel value.
philpem@5 12706 CImg<T>& sqrt() {
philpem@5 12707 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sqrt((double)(*ptr));
philpem@5 12708 return *this;
philpem@5 12709 }
philpem@5 12710
philpem@5 12711 CImg<Tfloat> get_sqrt() const {
philpem@5 12712 return CImg<Tfloat>(*this,false).sqrt();
philpem@5 12713 }
philpem@5 12714
philpem@5 12715 //! Compute the exponential of each pixel value.
philpem@5 12716 CImg<T>& exp() {
philpem@5 12717 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::exp((double)(*ptr));
philpem@5 12718 return *this;
philpem@5 12719 }
philpem@5 12720
philpem@5 12721 CImg<Tfloat> get_exp() const {
philpem@5 12722 return CImg<Tfloat>(*this,false).exp();
philpem@5 12723 }
philpem@5 12724
philpem@5 12725 //! Compute the log of each each pixel value.
philpem@5 12726 CImg<T>& log() {
philpem@5 12727 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log((double)(*ptr));
philpem@5 12728 return *this;
philpem@5 12729 }
philpem@5 12730
philpem@5 12731 CImg<Tfloat> get_log() const {
philpem@5 12732 return CImg<Tfloat>(*this,false).log();
philpem@5 12733 }
philpem@5 12734
philpem@5 12735 //! Compute the log10 of each each pixel value.
philpem@5 12736 CImg<T>& log10() {
philpem@5 12737 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::log10((double)(*ptr));
philpem@5 12738 return *this;
philpem@5 12739 }
philpem@5 12740
philpem@5 12741 CImg<Tfloat> get_log10() const {
philpem@5 12742 return CImg<Tfloat>(*this,false).log10();
philpem@5 12743 }
philpem@5 12744
philpem@5 12745 //! Compute the power by p of each pixel value.
philpem@5 12746 CImg<T>& pow(const double p) {
philpem@5 12747 if (p==0) return fill(1);
philpem@5 12748 if (p==0.5) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = (T)cimg_std::sqrt((double)val); } return *this; }
philpem@5 12749 if (p==1) return *this;
philpem@5 12750 if (p==2) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val; } return *this; }
philpem@5 12751 if (p==3) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val; } return *this; }
philpem@5 12752 if (p==4) { cimg_for(*this,ptr,T) { const T val = *ptr; *ptr = val*val*val*val; } return *this; }
philpem@5 12753 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::pow((double)(*ptr),p);
philpem@5 12754 return *this;
philpem@5 12755 }
philpem@5 12756
philpem@5 12757 CImg<Tfloat> get_pow(const double p) const {
philpem@5 12758 return CImg<Tfloat>(*this,false).pow(p);
philpem@5 12759 }
philpem@5 12760
philpem@5 12761 //! Compute the power of each pixel value.
philpem@5 12762 template<typename t>
philpem@5 12763 CImg<T>& pow(const CImg<t>& img) {
philpem@5 12764 if (is_overlapped(img)) return pow(+img);
philpem@5 12765 t *ptrs = img.data;
philpem@5 12766 T *ptrf = data + cimg::min(size(),img.size());
philpem@5 12767 for (T* ptrd = data; ptrd<ptrf; ++ptrd) (*ptrd) = (T)cimg_std::pow((double)*ptrd,(double)(*(ptrs++)));
philpem@5 12768 return *this;
philpem@5 12769 }
philpem@5 12770
philpem@5 12771 template<typename t>
philpem@5 12772 CImg<Tfloat> get_pow(const CImg<t>& img) const {
philpem@5 12773 return CImg<Tfloat>(*this,false).pow(img);
philpem@5 12774 }
philpem@5 12775
philpem@5 12776 //! Compute the absolute value of each pixel value.
philpem@5 12777 CImg<T>& abs() {
philpem@5 12778 cimg_for(*this,ptr,T) (*ptr) = cimg::abs(*ptr);
philpem@5 12779 return *this;
philpem@5 12780 }
philpem@5 12781
philpem@5 12782 CImg<Tfloat> get_abs() const {
philpem@5 12783 return CImg<Tfloat>(*this,false).abs();
philpem@5 12784 }
philpem@5 12785
philpem@5 12786 //! Compute the cosinus of each pixel value.
philpem@5 12787 CImg<T>& cos() {
philpem@5 12788 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::cos((double)(*ptr));
philpem@5 12789 return *this;
philpem@5 12790 }
philpem@5 12791
philpem@5 12792 CImg<Tfloat> get_cos() const {
philpem@5 12793 return CImg<Tfloat>(*this,false).cos();
philpem@5 12794 }
philpem@5 12795
philpem@5 12796 //! Compute the sinus of each pixel value.
philpem@5 12797 CImg<T>& sin() {
philpem@5 12798 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::sin((double)(*ptr));
philpem@5 12799 return *this;
philpem@5 12800 }
philpem@5 12801
philpem@5 12802 CImg<Tfloat> get_sin() const {
philpem@5 12803 return CImg<Tfloat>(*this,false).sin();
philpem@5 12804 }
philpem@5 12805
philpem@5 12806 //! Compute the tangent of each pixel.
philpem@5 12807 CImg<T>& tan() {
philpem@5 12808 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::tan((double)(*ptr));
philpem@5 12809 return *this;
philpem@5 12810 }
philpem@5 12811
philpem@5 12812 CImg<Tfloat> get_tan() const {
philpem@5 12813 return CImg<Tfloat>(*this,false).tan();
philpem@5 12814 }
philpem@5 12815
philpem@5 12816 //! Compute the arc-cosine of each pixel value.
philpem@5 12817 CImg<T>& acos() {
philpem@5 12818 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::acos((double)(*ptr));
philpem@5 12819 return *this;
philpem@5 12820 }
philpem@5 12821
philpem@5 12822 CImg<Tfloat> get_acos() const {
philpem@5 12823 return CImg<Tfloat>(*this,false).acos();
philpem@5 12824 }
philpem@5 12825
philpem@5 12826 //! Compute the arc-sinus of each pixel value.
philpem@5 12827 CImg<T>& asin() {
philpem@5 12828 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::asin((double)(*ptr));
philpem@5 12829 return *this;
philpem@5 12830 }
philpem@5 12831
philpem@5 12832 CImg<Tfloat> get_asin() const {
philpem@5 12833 return CImg<Tfloat>(*this,false).asin();
philpem@5 12834 }
philpem@5 12835
philpem@5 12836 //! Compute the arc-tangent of each pixel.
philpem@5 12837 CImg<T>& atan() {
philpem@5 12838 cimg_for(*this,ptr,T) (*ptr) = (T)cimg_std::atan((double)(*ptr));
philpem@5 12839 return *this;
philpem@5 12840 }
philpem@5 12841
philpem@5 12842 CImg<Tfloat> get_atan() const {
philpem@5 12843 return CImg<Tfloat>(*this,false).atan();
philpem@5 12844 }
philpem@5 12845
philpem@5 12846 //! Compute image with rounded pixel values.
philpem@5 12847 /**
philpem@5 12848 \param x Rounding precision.
philpem@5 12849 \param rounding_type Roundin type, can be 0 (nearest), 1 (forward), -1(backward).
philpem@5 12850 **/
philpem@5 12851 CImg<T>& round(const float x, const int rounding_type=0) {
philpem@5 12852 cimg_for(*this,ptr,T) (*ptr) = (T)cimg::round(*ptr,x,rounding_type);
philpem@5 12853 return *this;
philpem@5 12854 }
philpem@5 12855
philpem@5 12856 CImg<T> get_round(const float x, const unsigned int rounding_type=0) const {
philpem@5 12857 return (+*this).round(x,rounding_type);
philpem@5 12858 }
philpem@5 12859
philpem@5 12860 //! Fill the instance image with random values between specified range.
philpem@5 12861 CImg<T>& rand(const T val_min, const T val_max) {
philpem@5 12862 const float delta = (float)val_max - (float)val_min;
philpem@5 12863 cimg_for(*this,ptr,T) *ptr = (T)(val_min + cimg::rand()*delta);
philpem@5 12864 return *this;
philpem@5 12865 }
philpem@5 12866
philpem@5 12867 CImg<T> get_rand(const T val_min, const T val_max) const {
philpem@5 12868 return (+*this).rand(val_min,val_max);
philpem@5 12869 }
philpem@5 12870
philpem@5 12871 //@}
philpem@5 12872 //-----------------------------------
philpem@5 12873 //
philpem@5 12874 //! \name Usual Image Transformations
philpem@5 12875 //@{
philpem@5 12876 //-----------------------------------
philpem@5 12877
philpem@5 12878 //! Fill an image by a value \p val.
philpem@5 12879 /**
philpem@5 12880 \param val = fill value
philpem@5 12881 \note All pixel values of the instance image will be initialized by \p val.
philpem@5 12882 **/
philpem@5 12883 CImg<T>& fill(const T val) {
philpem@5 12884 if (is_empty()) return *this;
philpem@5 12885 if (val && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr = val;
philpem@5 12886 else cimg_std::memset(data,(int)val,size()*sizeof(T));
philpem@5 12887 return *this;
philpem@5 12888 }
philpem@5 12889
philpem@5 12890 CImg<T> get_fill(const T val) const {
philpem@5 12891 return CImg<T>(width,height,depth,dim).fill(val);
philpem@5 12892 }
philpem@5 12893
philpem@5 12894 //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively.
philpem@5 12895 CImg<T>& fill(const T val0, const T val1) {
philpem@5 12896 if (is_empty()) return *this;
philpem@5 12897 T *ptr, *ptr_end = end()-1;
philpem@5 12898 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; }
philpem@5 12899 if (ptr!=ptr_end+1) *(ptr++) = val0;
philpem@5 12900 return *this;
philpem@5 12901 }
philpem@5 12902
philpem@5 12903 CImg<T> get_fill(const T val0, const T val1) const {
philpem@5 12904 return CImg<T>(width,height,depth,dim).fill(val0,val1);
philpem@5 12905 }
philpem@5 12906
philpem@5 12907 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2.
philpem@5 12908 CImg<T>& fill(const T val0, const T val1, const T val2) {
philpem@5 12909 if (is_empty()) return *this;
philpem@5 12910 T *ptr, *ptr_end = end()-2;
philpem@5 12911 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; }
philpem@5 12912 ptr_end+=2;
philpem@5 12913 switch (ptr_end-ptr) {
philpem@5 12914 case 2 : *(--ptr_end) = val1;
philpem@5 12915 case 1 : *(--ptr_end) = val0;
philpem@5 12916 }
philpem@5 12917 return *this;
philpem@5 12918 }
philpem@5 12919
philpem@5 12920 CImg<T> get_fill(const T val0, const T val1, const T val2) const {
philpem@5 12921 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2);
philpem@5 12922 }
philpem@5 12923
philpem@5 12924 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3.
philpem@5 12925 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3) {
philpem@5 12926 if (is_empty()) return *this;
philpem@5 12927 T *ptr, *ptr_end = end()-3;
philpem@5 12928 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; }
philpem@5 12929 ptr_end+=3;
philpem@5 12930 switch (ptr_end-ptr) {
philpem@5 12931 case 3 : *(--ptr_end) = val2;
philpem@5 12932 case 2 : *(--ptr_end) = val1;
philpem@5 12933 case 1 : *(--ptr_end) = val0;
philpem@5 12934 }
philpem@5 12935 return *this;
philpem@5 12936 }
philpem@5 12937
philpem@5 12938 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3) const {
philpem@5 12939 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3);
philpem@5 12940 }
philpem@5 12941
philpem@5 12942 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4.
philpem@5 12943 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4) {
philpem@5 12944 if (is_empty()) return *this;
philpem@5 12945 T *ptr, *ptr_end = end()-4;
philpem@5 12946 for (ptr = data; ptr<ptr_end; ) { *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; }
philpem@5 12947 ptr_end+=4;
philpem@5 12948 switch (ptr_end-ptr) {
philpem@5 12949 case 4 : *(--ptr_end) = val3;
philpem@5 12950 case 3 : *(--ptr_end) = val2;
philpem@5 12951 case 2 : *(--ptr_end) = val1;
philpem@5 12952 case 1 : *(--ptr_end) = val0;
philpem@5 12953 }
philpem@5 12954 return *this;
philpem@5 12955 }
philpem@5 12956
philpem@5 12957 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4) const {
philpem@5 12958 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4);
philpem@5 12959 }
philpem@5 12960
philpem@5 12961 //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5.
philpem@5 12962 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) {
philpem@5 12963 if (is_empty()) return *this;
philpem@5 12964 T *ptr, *ptr_end = end()-5;
philpem@5 12965 for (ptr = data; ptr<ptr_end; ) {
philpem@5 12966 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 12967 }
philpem@5 12968 ptr_end+=5;
philpem@5 12969 switch (ptr_end-ptr) {
philpem@5 12970 case 5 : *(--ptr_end) = val4;
philpem@5 12971 case 4 : *(--ptr_end) = val3;
philpem@5 12972 case 3 : *(--ptr_end) = val2;
philpem@5 12973 case 2 : *(--ptr_end) = val1;
philpem@5 12974 case 1 : *(--ptr_end) = val0;
philpem@5 12975 }
philpem@5 12976 return *this;
philpem@5 12977 }
philpem@5 12978
philpem@5 12979 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5) const {
philpem@5 12980 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5);
philpem@5 12981 }
philpem@5 12982
philpem@5 12983 //! Fill sequentially pixel values.
philpem@5 12984 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) {
philpem@5 12985 if (is_empty()) return *this;
philpem@5 12986 T *ptr, *ptr_end = end()-6;
philpem@5 12987 for (ptr = data; ptr<ptr_end; ) {
philpem@5 12988 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6;
philpem@5 12989 }
philpem@5 12990 ptr_end+=6;
philpem@5 12991 switch (ptr_end-ptr) {
philpem@5 12992 case 6 : *(--ptr_end) = val5;
philpem@5 12993 case 5 : *(--ptr_end) = val4;
philpem@5 12994 case 4 : *(--ptr_end) = val3;
philpem@5 12995 case 3 : *(--ptr_end) = val2;
philpem@5 12996 case 2 : *(--ptr_end) = val1;
philpem@5 12997 case 1 : *(--ptr_end) = val0;
philpem@5 12998 }
philpem@5 12999 return *this;
philpem@5 13000 }
philpem@5 13001
philpem@5 13002 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6) const {
philpem@5 13003 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6);
philpem@5 13004 }
philpem@5 13005
philpem@5 13006 //! Fill sequentially pixel values.
philpem@5 13007 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13008 const T val7) {
philpem@5 13009 if (is_empty()) return *this;
philpem@5 13010 T *ptr, *ptr_end = end()-7;
philpem@5 13011 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13012 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3;
philpem@5 13013 *(ptr++) = val4; *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7;
philpem@5 13014 }
philpem@5 13015 ptr_end+=7;
philpem@5 13016 switch (ptr_end-ptr) {
philpem@5 13017 case 7 : *(--ptr_end) = val6;
philpem@5 13018 case 6 : *(--ptr_end) = val5;
philpem@5 13019 case 5 : *(--ptr_end) = val4;
philpem@5 13020 case 4 : *(--ptr_end) = val3;
philpem@5 13021 case 3 : *(--ptr_end) = val2;
philpem@5 13022 case 2 : *(--ptr_end) = val1;
philpem@5 13023 case 1 : *(--ptr_end) = val0;
philpem@5 13024 }
philpem@5 13025 return *this;
philpem@5 13026 }
philpem@5 13027
philpem@5 13028 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13029 const T val7) const {
philpem@5 13030 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7);
philpem@5 13031 }
philpem@5 13032
philpem@5 13033 //! Fill sequentially pixel values.
philpem@5 13034 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13035 const T val7, const T val8) {
philpem@5 13036 if (is_empty()) return *this;
philpem@5 13037 T *ptr, *ptr_end = end()-8;
philpem@5 13038 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13039 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2;
philpem@5 13040 *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13041 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8;
philpem@5 13042 }
philpem@5 13043 ptr_end+=8;
philpem@5 13044 switch (ptr_end-ptr) {
philpem@5 13045 case 8 : *(--ptr_end) = val7;
philpem@5 13046 case 7 : *(--ptr_end) = val6;
philpem@5 13047 case 6 : *(--ptr_end) = val5;
philpem@5 13048 case 5 : *(--ptr_end) = val4;
philpem@5 13049 case 4 : *(--ptr_end) = val3;
philpem@5 13050 case 3 : *(--ptr_end) = val2;
philpem@5 13051 case 2 : *(--ptr_end) = val1;
philpem@5 13052 case 1 : *(--ptr_end) = val0;
philpem@5 13053 }
philpem@5 13054 return *this;
philpem@5 13055 }
philpem@5 13056
philpem@5 13057 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13058 const T val7, const T val8) const {
philpem@5 13059 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8);
philpem@5 13060 }
philpem@5 13061
philpem@5 13062 //! Fill sequentially pixel values.
philpem@5 13063 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13064 const T val7, const T val8, const T val9) {
philpem@5 13065 if (is_empty()) return *this;
philpem@5 13066 T *ptr, *ptr_end = end()-9;
philpem@5 13067 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13068 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
philpem@5 13069 *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
philpem@5 13070 }
philpem@5 13071 ptr_end+=9;
philpem@5 13072 switch (ptr_end-ptr) {
philpem@5 13073 case 9 : *(--ptr_end) = val8;
philpem@5 13074 case 8 : *(--ptr_end) = val7;
philpem@5 13075 case 7 : *(--ptr_end) = val6;
philpem@5 13076 case 6 : *(--ptr_end) = val5;
philpem@5 13077 case 5 : *(--ptr_end) = val4;
philpem@5 13078 case 4 : *(--ptr_end) = val3;
philpem@5 13079 case 3 : *(--ptr_end) = val2;
philpem@5 13080 case 2 : *(--ptr_end) = val1;
philpem@5 13081 case 1 : *(--ptr_end) = val0;
philpem@5 13082 }
philpem@5 13083 return *this;
philpem@5 13084 }
philpem@5 13085
philpem@5 13086 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13087 const T val7, const T val8, const T val9) const {
philpem@5 13088 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9);
philpem@5 13089 }
philpem@5 13090
philpem@5 13091 //! Fill sequentially pixel values.
philpem@5 13092 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13093 const T val7, const T val8, const T val9, const T val10) {
philpem@5 13094 if (is_empty()) return *this;
philpem@5 13095 T *ptr, *ptr_end = end()-10;
philpem@5 13096 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13097 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4;
philpem@5 13098 *(ptr++) = val5; *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9;
philpem@5 13099 *(ptr++) = val10;
philpem@5 13100 }
philpem@5 13101 ptr_end+=10;
philpem@5 13102 switch (ptr_end-ptr) {
philpem@5 13103 case 10 : *(--ptr_end) = val9;
philpem@5 13104 case 9 : *(--ptr_end) = val8;
philpem@5 13105 case 8 : *(--ptr_end) = val7;
philpem@5 13106 case 7 : *(--ptr_end) = val6;
philpem@5 13107 case 6 : *(--ptr_end) = val5;
philpem@5 13108 case 5 : *(--ptr_end) = val4;
philpem@5 13109 case 4 : *(--ptr_end) = val3;
philpem@5 13110 case 3 : *(--ptr_end) = val2;
philpem@5 13111 case 2 : *(--ptr_end) = val1;
philpem@5 13112 case 1 : *(--ptr_end) = val0;
philpem@5 13113 }
philpem@5 13114 return *this;
philpem@5 13115 }
philpem@5 13116
philpem@5 13117 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13118 const T val7, const T val8, const T val9, const T val10) const {
philpem@5 13119 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10);
philpem@5 13120 }
philpem@5 13121
philpem@5 13122 //! Fill sequentially pixel values.
philpem@5 13123 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13124 const T val7, const T val8, const T val9, const T val10, const T val11) {
philpem@5 13125 if (is_empty()) return *this;
philpem@5 13126 T *ptr, *ptr_end = end()-11;
philpem@5 13127 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13128 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13129 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
philpem@5 13130 }
philpem@5 13131 ptr_end+=11;
philpem@5 13132 switch (ptr_end-ptr) {
philpem@5 13133 case 11 : *(--ptr_end) = val10;
philpem@5 13134 case 10 : *(--ptr_end) = val9;
philpem@5 13135 case 9 : *(--ptr_end) = val8;
philpem@5 13136 case 8 : *(--ptr_end) = val7;
philpem@5 13137 case 7 : *(--ptr_end) = val6;
philpem@5 13138 case 6 : *(--ptr_end) = val5;
philpem@5 13139 case 5 : *(--ptr_end) = val4;
philpem@5 13140 case 4 : *(--ptr_end) = val3;
philpem@5 13141 case 3 : *(--ptr_end) = val2;
philpem@5 13142 case 2 : *(--ptr_end) = val1;
philpem@5 13143 case 1 : *(--ptr_end) = val0;
philpem@5 13144 }
philpem@5 13145 return *this;
philpem@5 13146 }
philpem@5 13147
philpem@5 13148 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13149 const T val7, const T val8, const T val9, const T val10, const T val11) const {
philpem@5 13150 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11);
philpem@5 13151 }
philpem@5 13152
philpem@5 13153 //! Fill sequentially pixel values.
philpem@5 13154 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13155 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) {
philpem@5 13156 if (is_empty()) return *this;
philpem@5 13157 T *ptr, *ptr_end = end()-12;
philpem@5 13158 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13159 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13160 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
philpem@5 13161 *(ptr++) = val12;
philpem@5 13162 }
philpem@5 13163 ptr_end+=12;
philpem@5 13164 switch (ptr_end-ptr) {
philpem@5 13165 case 12 : *(--ptr_end) = val11;
philpem@5 13166 case 11 : *(--ptr_end) = val10;
philpem@5 13167 case 10 : *(--ptr_end) = val9;
philpem@5 13168 case 9 : *(--ptr_end) = val8;
philpem@5 13169 case 8 : *(--ptr_end) = val7;
philpem@5 13170 case 7 : *(--ptr_end) = val6;
philpem@5 13171 case 6 : *(--ptr_end) = val5;
philpem@5 13172 case 5 : *(--ptr_end) = val4;
philpem@5 13173 case 4 : *(--ptr_end) = val3;
philpem@5 13174 case 3 : *(--ptr_end) = val2;
philpem@5 13175 case 2 : *(--ptr_end) = val1;
philpem@5 13176 case 1 : *(--ptr_end) = val0;
philpem@5 13177 }
philpem@5 13178 return *this;
philpem@5 13179 }
philpem@5 13180
philpem@5 13181 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13182 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12) const {
philpem@5 13183 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12);
philpem@5 13184 }
philpem@5 13185
philpem@5 13186 //! Fill sequentially pixel values.
philpem@5 13187 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13188 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13189 const T val13) {
philpem@5 13190 if (is_empty()) return *this;
philpem@5 13191 T *ptr, *ptr_end = end()-13;
philpem@5 13192 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13193 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13194 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
philpem@5 13195 *(ptr++) = val12; *(ptr++) = val13;
philpem@5 13196 }
philpem@5 13197 ptr_end+=13;
philpem@5 13198 switch (ptr_end-ptr) {
philpem@5 13199 case 13 : *(--ptr_end) = val12;
philpem@5 13200 case 12 : *(--ptr_end) = val11;
philpem@5 13201 case 11 : *(--ptr_end) = val10;
philpem@5 13202 case 10 : *(--ptr_end) = val9;
philpem@5 13203 case 9 : *(--ptr_end) = val8;
philpem@5 13204 case 8 : *(--ptr_end) = val7;
philpem@5 13205 case 7 : *(--ptr_end) = val6;
philpem@5 13206 case 6 : *(--ptr_end) = val5;
philpem@5 13207 case 5 : *(--ptr_end) = val4;
philpem@5 13208 case 4 : *(--ptr_end) = val3;
philpem@5 13209 case 3 : *(--ptr_end) = val2;
philpem@5 13210 case 2 : *(--ptr_end) = val1;
philpem@5 13211 case 1 : *(--ptr_end) = val0;
philpem@5 13212 }
philpem@5 13213 return *this;
philpem@5 13214 }
philpem@5 13215
philpem@5 13216 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13217 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13218 const T val13) const {
philpem@5 13219 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
philpem@5 13220 val13);
philpem@5 13221 }
philpem@5 13222
philpem@5 13223 //! Fill sequentially pixel values.
philpem@5 13224 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13225 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13226 const T val13, const T val14) {
philpem@5 13227 if (is_empty()) return *this;
philpem@5 13228 T *ptr, *ptr_end = end()-14;
philpem@5 13229 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13230 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13231 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
philpem@5 13232 *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14;
philpem@5 13233 }
philpem@5 13234 ptr_end+=14;
philpem@5 13235 switch (ptr_end-ptr) {
philpem@5 13236 case 14 : *(--ptr_end) = val13;
philpem@5 13237 case 13 : *(--ptr_end) = val12;
philpem@5 13238 case 12 : *(--ptr_end) = val11;
philpem@5 13239 case 11 : *(--ptr_end) = val10;
philpem@5 13240 case 10 : *(--ptr_end) = val9;
philpem@5 13241 case 9 : *(--ptr_end) = val8;
philpem@5 13242 case 8 : *(--ptr_end) = val7;
philpem@5 13243 case 7 : *(--ptr_end) = val6;
philpem@5 13244 case 6 : *(--ptr_end) = val5;
philpem@5 13245 case 5 : *(--ptr_end) = val4;
philpem@5 13246 case 4 : *(--ptr_end) = val3;
philpem@5 13247 case 3 : *(--ptr_end) = val2;
philpem@5 13248 case 2 : *(--ptr_end) = val1;
philpem@5 13249 case 1 : *(--ptr_end) = val0;
philpem@5 13250 }
philpem@5 13251 return *this;
philpem@5 13252 }
philpem@5 13253
philpem@5 13254 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13255 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13256 const T val13, const T val14) const {
philpem@5 13257 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
philpem@5 13258 val13,val14);
philpem@5 13259 }
philpem@5 13260
philpem@5 13261 //! Fill sequentially pixel values.
philpem@5 13262 CImg<T>& fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13263 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13264 const T val13, const T val14, const T val15) {
philpem@5 13265 if (is_empty()) return *this;
philpem@5 13266 T *ptr, *ptr_end = end()-15;
philpem@5 13267 for (ptr = data; ptr<ptr_end; ) {
philpem@5 13268 *(ptr++) = val0; *(ptr++) = val1; *(ptr++) = val2; *(ptr++) = val3; *(ptr++) = val4; *(ptr++) = val5;
philpem@5 13269 *(ptr++) = val6; *(ptr++) = val7; *(ptr++) = val8; *(ptr++) = val9; *(ptr++) = val10; *(ptr++) = val11;
philpem@5 13270 *(ptr++) = val12; *(ptr++) = val13; *(ptr++) = val14; *(ptr++) = val15;
philpem@5 13271 }
philpem@5 13272 ptr_end+=15;
philpem@5 13273 switch (ptr_end-ptr) {
philpem@5 13274 case 15 : *(--ptr_end) = val14;
philpem@5 13275 case 14 : *(--ptr_end) = val13;
philpem@5 13276 case 13 : *(--ptr_end) = val12;
philpem@5 13277 case 12 : *(--ptr_end) = val11;
philpem@5 13278 case 11 : *(--ptr_end) = val10;
philpem@5 13279 case 10 : *(--ptr_end) = val9;
philpem@5 13280 case 9 : *(--ptr_end) = val8;
philpem@5 13281 case 8 : *(--ptr_end) = val7;
philpem@5 13282 case 7 : *(--ptr_end) = val6;
philpem@5 13283 case 6 : *(--ptr_end) = val5;
philpem@5 13284 case 5 : *(--ptr_end) = val4;
philpem@5 13285 case 4 : *(--ptr_end) = val3;
philpem@5 13286 case 3 : *(--ptr_end) = val2;
philpem@5 13287 case 2 : *(--ptr_end) = val1;
philpem@5 13288 case 1 : *(--ptr_end) = val0;
philpem@5 13289 }
philpem@5 13290 return *this;
philpem@5 13291 }
philpem@5 13292
philpem@5 13293 CImg<T> get_fill(const T val0, const T val1, const T val2, const T val3, const T val4, const T val5, const T val6,
philpem@5 13294 const T val7, const T val8, const T val9, const T val10, const T val11, const T val12,
philpem@5 13295 const T val13, const T val14, const T val15) const {
philpem@5 13296 return CImg<T>(width,height,depth,dim).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,
philpem@5 13297 val13,val14,val15);
philpem@5 13298 }
philpem@5 13299
philpem@5 13300 //! Fill image values according to the values found in the specified string.
philpem@5 13301 CImg<T>& fill(const char *const values, const bool repeat_pattern) {
philpem@5 13302 if (is_empty() || !values) return *this;
philpem@5 13303 T *ptrd = data, *ptr_end = data + size();
philpem@5 13304 const char *nvalues = values;
philpem@5 13305 const unsigned int siz = size();
philpem@5 13306 char cval[64] = { 0 }, sep = 0;
philpem@5 13307 int err = 0; double val = 0; unsigned int nb = 0;
philpem@5 13308 while ((err=cimg_std::sscanf(nvalues,"%63[ \n\t0-9e.+-]%c",cval,&sep))>0 &&
philpem@5 13309 cimg_std::sscanf(cval,"%lf",&val)>0 && nb<siz) {
philpem@5 13310 nvalues += cimg::strlen(cval);
philpem@5 13311 *(ptrd++) = (T)val;
philpem@5 13312 ++nb;
philpem@5 13313 if (err!=2) break; else ++nvalues;
philpem@5 13314 }
philpem@5 13315 if (repeat_pattern && nb) for (T *ptrs = data; ptrd<ptr_end; ++ptrs) *(ptrd++) = *ptrs;
philpem@5 13316 return *this;
philpem@5 13317 }
philpem@5 13318
philpem@5 13319 CImg<T> get_fill(const char *const values, const bool repeat_pattern) const {
philpem@5 13320 return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
philpem@5 13321 }
philpem@5 13322
philpem@5 13323 //! Fill image values according to the values found in the specified image.
philpem@5 13324 template<typename t>
philpem@5 13325 CImg<T>& fill(const CImg<t>& values, const bool repeat_pattern=true) {
philpem@5 13326 if (is_empty() || !values) return *this;
philpem@5 13327 T *ptrd = data, *ptrd_end = ptrd + size();
philpem@5 13328 for (t *ptrs = values.data, *ptrs_end = ptrs + values.size(); ptrs<ptrs_end && ptrd<ptrd_end; ++ptrs) *(ptrd++) = (T)*ptrs;
philpem@5 13329 if (repeat_pattern && ptrd<ptrd_end) for (T *ptrs = data; ptrd<ptrd_end; ++ptrs) *(ptrd++) = *ptrs;
philpem@5 13330 return *this;
philpem@5 13331 }
philpem@5 13332
philpem@5 13333 template<typename t>
philpem@5 13334 CImg<T> get_fill(const CImg<t>& values, const bool repeat_pattern=true) const {
philpem@5 13335 return repeat_pattern?CImg<T>(width,height,depth,dim).fill(values,repeat_pattern):(+*this).fill(values,repeat_pattern);
philpem@5 13336 }
philpem@5 13337
philpem@5 13338 //! Fill image values along the X-axis at the specified pixel position (y,z,v).
philpem@5 13339 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const int a0, ...) {
philpem@5 13340 #define _cimg_fill1(x,y,z,v,off,siz,t) { \
philpem@5 13341 va_list ap; va_start(ap,a0); T *ptrd = ptr(x,y,z,v); *ptrd = (T)a0; \
philpem@5 13342 for (unsigned int k = 1; k<siz; ++k) { ptrd+=off; *ptrd = (T)va_arg(ap,t); } \
philpem@5 13343 va_end(ap); }
philpem@5 13344 if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,int);
philpem@5 13345 return *this;
philpem@5 13346 }
philpem@5 13347
philpem@5 13348 CImg<T>& fillX(const unsigned int y, const unsigned int z, const unsigned int v, const double a0, ...) {
philpem@5 13349 if (y<height && z<depth && v<dim) _cimg_fill1(0,y,z,v,1,width,double);
philpem@5 13350 return *this;
philpem@5 13351 }
philpem@5 13352
philpem@5 13353 //! Fill image values along the Y-axis at the specified pixel position (x,z,v).
philpem@5 13354 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const int a0, ...) {
philpem@5 13355 if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,int);
philpem@5 13356 return *this;
philpem@5 13357 }
philpem@5 13358
philpem@5 13359 CImg<T>& fillY(const unsigned int x, const unsigned int z, const unsigned int v, const double a0, ...) {
philpem@5 13360 if (x<width && z<depth && v<dim) _cimg_fill1(x,0,z,v,width,height,double);
philpem@5 13361 return *this;
philpem@5 13362 }
philpem@5 13363
philpem@5 13364 //! Fill image values along the Z-axis at the specified pixel position (x,y,v).
philpem@5 13365 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const int a0, ...) {
philpem@5 13366 const unsigned int wh = width*height;
philpem@5 13367 if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,int);
philpem@5 13368 return *this;
philpem@5 13369 }
philpem@5 13370
philpem@5 13371 CImg<T>& fillZ(const unsigned int x, const unsigned int y, const unsigned int v, const double a0, ...) {
philpem@5 13372 const unsigned int wh = width*height;
philpem@5 13373 if (x<width && y<height && v<dim) _cimg_fill1(x,y,0,v,wh,depth,double);
philpem@5 13374 return *this;
philpem@5 13375 }
philpem@5 13376
philpem@5 13377 //! Fill image values along the V-axis at the specified pixel position (x,y,z).
philpem@5 13378 CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) {
philpem@5 13379 const unsigned int whz = width*height*depth;
philpem@5 13380 if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,int);
philpem@5 13381 return *this;
philpem@5 13382 }
philpem@5 13383
philpem@5 13384 CImg<T>& fillV(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) {
philpem@5 13385 const unsigned int whz = width*height*depth;
philpem@5 13386 if (x<width && y<height && z<depth) _cimg_fill1(x,y,z,0,whz,dim,double);
philpem@5 13387 return *this;
philpem@5 13388 }
philpem@5 13389
philpem@5 13390 //! Linear normalization of the pixel values between \a a and \a b.
philpem@5 13391 CImg<T>& normalize(const T a, const T b) {
philpem@5 13392 if (is_empty()) return *this;
philpem@5 13393 const T na = a<b?a:b, nb = a<b?b:a;
philpem@5 13394 T m, M = maxmin(m);
philpem@5 13395 const Tfloat fm = (Tfloat)m, fM = (Tfloat)M;
philpem@5 13396 if (m==M) return fill(0);
philpem@5 13397 if (m!=na || M!=nb) cimg_for(*this,ptr,T) *ptr = (T)((*ptr-fm)/(fM-fm)*(nb-na)+na);
philpem@5 13398 return *this;
philpem@5 13399 }
philpem@5 13400
philpem@5 13401 CImg<T> get_normalize(const T a, const T b) const {
philpem@5 13402 return (+*this).normalize(a,b);
philpem@5 13403 }
philpem@5 13404
philpem@5 13405 //! Cut pixel values between \a a and \a b.
philpem@5 13406 CImg<T>& cut(const T a, const T b) {
philpem@5 13407 if (is_empty()) return *this;
philpem@5 13408 const T na = a<b?a:b, nb = a<b?b:a;
philpem@5 13409 cimg_for(*this,ptr,T) *ptr = (*ptr<na)?na:((*ptr>nb)?nb:*ptr);
philpem@5 13410 return *this;
philpem@5 13411 }
philpem@5 13412
philpem@5 13413 CImg<T> get_cut(const T a, const T b) const {
philpem@5 13414 return (+*this).cut(a,b);
philpem@5 13415 }
philpem@5 13416
philpem@5 13417 //! Quantize pixel values into \n levels.
philpem@5 13418 CImg<T>& quantize(const unsigned int n, const bool keep_range=true) {
philpem@5 13419 if (is_empty()) return *this;
philpem@5 13420 if (!n)
philpem@5 13421 throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.",
philpem@5 13422 pixel_type());
philpem@5 13423 Tfloat m, M = (Tfloat)maxmin(m), range = M - m;
philpem@5 13424 if (range>0) {
philpem@5 13425 if (keep_range) cimg_for(*this,ptr,T) {
philpem@5 13426 const unsigned int val = (unsigned int)((*ptr-m)*n/range);
philpem@5 13427 *ptr = (T)(m + cimg::min(val,n-1)*range/n);
philpem@5 13428 } else cimg_for(*this,ptr,T) {
philpem@5 13429 const unsigned int val = (unsigned int)((*ptr-m)*n/range);
philpem@5 13430 *ptr = (T)cimg::min(val,n-1);
philpem@5 13431 }
philpem@5 13432 }
philpem@5 13433 return *this;
philpem@5 13434 }
philpem@5 13435
philpem@5 13436 CImg<T> get_quantize(const unsigned int n, const bool keep_range=true) const {
philpem@5 13437 return (+*this).quantize(n,keep_range);
philpem@5 13438 }
philpem@5 13439
philpem@5 13440 //! Threshold the image.
philpem@5 13441 /**
philpem@5 13442 \param value Threshold value.
philpem@5 13443 \param soft Enable soft thresholding.
philpem@5 13444 \param strict Tells if the threshold is strict.
philpem@5 13445 **/
philpem@5 13446 CImg<T>& threshold(const T value, const bool soft=false, const bool strict=false) {
philpem@5 13447 if (is_empty()) return *this;
philpem@5 13448 if (strict) {
philpem@5 13449 if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>value?(T)(v-value):v<-value?(T)(v+value):(T)0; }
philpem@5 13450 else cimg_for(*this,ptr,T) *ptr = *ptr>value?(T)1:(T)0;
philpem@5 13451 } else {
philpem@5 13452 if (soft) cimg_for(*this,ptr,T) { const T v = *ptr; *ptr = v>=value?(T)(v-value):v<=-value?(T)(v+value):(T)0; }
philpem@5 13453 else cimg_for(*this,ptr,T) *ptr = *ptr>=value?(T)1:(T)0;
philpem@5 13454 }
philpem@5 13455 return *this;
philpem@5 13456 }
philpem@5 13457
philpem@5 13458 CImg<T> get_threshold(const T value, const bool soft=false, const bool strict=false) const {
philpem@5 13459 return (+*this).threshold(value,soft,strict);
philpem@5 13460 }
philpem@5 13461
philpem@5 13462 //! Rotate an image.
philpem@5 13463 /**
philpem@5 13464 \param angle = rotation angle (in degrees).
philpem@5 13465 \param cond = rotation type. can be :
philpem@5 13466 - 0 = zero-value at borders
philpem@5 13467 - 1 = nearest pixel.
philpem@5 13468 - 2 = Fourier style.
philpem@5 13469 \note Returned image will probably have a different size than the instance image *this.
philpem@5 13470 **/
philpem@5 13471 CImg<T>& rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) {
philpem@5 13472 return get_rotate(angle,border_conditions,interpolation).transfer_to(*this);
philpem@5 13473 }
philpem@5 13474
philpem@5 13475 CImg<T> get_rotate(const float angle, const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
philpem@5 13476 if (is_empty()) return *this;
philpem@5 13477 CImg<T> dest;
philpem@5 13478 const float nangle = cimg::mod(angle,360.0f);
philpem@5 13479 if (border_conditions!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
philpem@5 13480 const int wm1 = dimx()-1, hm1 = dimy()-1;
philpem@5 13481 const int iangle = (int)nangle/90;
philpem@5 13482 switch (iangle) {
philpem@5 13483 case 1 : {
philpem@5 13484 dest.assign(height,width,depth,dim);
philpem@5 13485 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v);
philpem@5 13486 } break;
philpem@5 13487 case 2 : {
philpem@5 13488 dest.assign(width,height,depth,dim);
philpem@5 13489 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v);
philpem@5 13490 } break;
philpem@5 13491 case 3 : {
philpem@5 13492 dest.assign(height,width,depth,dim);
philpem@5 13493 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v);
philpem@5 13494 } break;
philpem@5 13495 default :
philpem@5 13496 return *this;
philpem@5 13497 }
philpem@5 13498 } else { // generic version
philpem@5 13499 const float
philpem@5 13500 rad = (float)(nangle*cimg::valuePI/180.0),
philpem@5 13501 ca = (float)cimg_std::cos(rad),
philpem@5 13502 sa = (float)cimg_std::sin(rad),
philpem@5 13503 ux = cimg::abs(width*ca), uy = cimg::abs(width*sa),
philpem@5 13504 vx = cimg::abs(height*sa), vy = cimg::abs(height*ca),
philpem@5 13505 w2 = 0.5f*width, h2 = 0.5f*height,
philpem@5 13506 dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy);
philpem@5 13507 dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim);
philpem@5 13508 switch (border_conditions) {
philpem@5 13509 case 0 : {
philpem@5 13510 switch (interpolation) {
philpem@5 13511 case 2 : {
philpem@5 13512 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13513 dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
philpem@5 13514 } break;
philpem@5 13515 case 1 : {
philpem@5 13516 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13517 dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v,0);
philpem@5 13518 } break;
philpem@5 13519 default : {
philpem@5 13520 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13521 dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0);
philpem@5 13522 }
philpem@5 13523 }
philpem@5 13524 } break;
philpem@5 13525 case 1 : {
philpem@5 13526 switch (interpolation) {
philpem@5 13527 case 2 :
philpem@5 13528 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13529 dest(x,y,z,v) = (T)cubic_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
philpem@5 13530 break;
philpem@5 13531 case 1 :
philpem@5 13532 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13533 dest(x,y,z,v) = (T)linear_atXY(w2 + (x-dw2)*ca + (y-dh2)*sa,h2 - (x-dw2)*sa + (y-dh2)*ca,z,v);
philpem@5 13534 break;
philpem@5 13535 default :
philpem@5 13536 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13537 dest(x,y,z,v) = atXY((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v);
philpem@5 13538 }
philpem@5 13539 } break;
philpem@5 13540 case 2 : {
philpem@5 13541 switch (interpolation) {
philpem@5 13542 case 2 :
philpem@5 13543 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13544 dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
philpem@5 13545 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
philpem@5 13546 break;
philpem@5 13547 case 1 :
philpem@5 13548 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13549 dest(x,y,z,v) = (T)linear_atXY(cimg::mod(w2 + (x-dw2)*ca + (y-dh2)*sa,(float)dimx()),
philpem@5 13550 cimg::mod(h2 - (x-dw2)*sa + (y-dh2)*ca,(float)dimy()),z,v);
philpem@5 13551 break;
philpem@5 13552 default :
philpem@5 13553 cimg_forXY(dest,x,y) cimg_forZV(*this,z,v)
philpem@5 13554 dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),dimx()),
philpem@5 13555 cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),dimy()),z,v);
philpem@5 13556 }
philpem@5 13557 } break;
philpem@5 13558 default :
philpem@5 13559 throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid border conditions %d (should be 0,1 or 2).",
philpem@5 13560 pixel_type(),border_conditions);
philpem@5 13561 }
philpem@5 13562 }
philpem@5 13563 return dest;
philpem@5 13564 }
philpem@5 13565
philpem@5 13566 //! Rotate an image around a center point (\c cx,\c cy).
philpem@5 13567 /**
philpem@5 13568 \param angle = rotation angle (in degrees).
philpem@5 13569 \param cx = X-coordinate of the rotation center.
philpem@5 13570 \param cy = Y-coordinate of the rotation center.
philpem@5 13571 \param zoom = zoom.
philpem@5 13572 \param cond = rotation type. can be :
philpem@5 13573 - 0 = zero-value at borders
philpem@5 13574 - 1 = repeat image at borders
philpem@5 13575 - 2 = zero-value at borders and linear interpolation
philpem@5 13576 **/
philpem@5 13577 CImg<T>& rotate(const float angle, const float cx, const float cy, const float zoom,
philpem@5 13578 const unsigned int border_conditions=3, const unsigned int interpolation=1) {
philpem@5 13579 return get_rotate(angle,cx,cy,zoom,border_conditions,interpolation).transfer_to(*this);
philpem@5 13580 }
philpem@5 13581
philpem@5 13582 CImg<T> get_rotate(const float angle, const float cx, const float cy, const float zoom,
philpem@5 13583 const unsigned int border_conditions=3, const unsigned int interpolation=1) const {
philpem@5 13584 if (interpolation>2)
philpem@5 13585 throw CImgArgumentException("CImg<%s>::get_rotate() : Invalid interpolation parameter %d (should be {0=none, 1=linear or 2=cubic}).",
philpem@5 13586 pixel_type(),interpolation);
philpem@5 13587 if (is_empty()) return *this;
philpem@5 13588 CImg<T> dest(width,height,depth,dim);
philpem@5 13589 const float nangle = cimg::mod(angle,360.0f);
philpem@5 13590 if (border_conditions!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles
philpem@5 13591 const int iangle = (int)nangle/90;
philpem@5 13592 switch (iangle) {
philpem@5 13593 case 1 : {
philpem@5 13594 dest.fill(0);
philpem@5 13595 const unsigned int
philpem@5 13596 xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
philpem@5 13597 ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
philpem@5 13598 xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
philpem@5 13599 yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
philpem@5 13600 cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
philpem@5 13601 dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v);
philpem@5 13602 } break;
philpem@5 13603 case 2 : {
philpem@5 13604 cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v);
philpem@5 13605 } break;
philpem@5 13606 case 3 : {
philpem@5 13607 dest.fill(0);
philpem@5 13608 const unsigned int
philpem@5 13609 xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height),
philpem@5 13610 ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width),
philpem@5 13611 xoff = xmin + cimg::min(0,(dimx()-dimy())/2),
philpem@5 13612 yoff = ymin + cimg::min(0,(dimy()-dimx())/2);
philpem@5 13613 cimg_forZV(dest,z,v) for (unsigned int y = ymin; y<ymax; ++y) for (unsigned int x = xmin; x<xmax; ++x)
philpem@5 13614 dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v);
philpem@5 13615 } break;
philpem@5 13616 default :
philpem@5 13617 return *this;
philpem@5 13618 }
philpem@5 13619 } else {
philpem@5 13620 const float
philpem@5 13621 rad = (float)((nangle*cimg::valuePI)/180.0),
philpem@5 13622 ca = (float)cimg_std::cos(rad)/zoom,
philpem@5 13623 sa = (float)cimg_std::sin(rad)/zoom;
philpem@5 13624 switch (border_conditions) { // generic version
philpem@5 13625 case 0 : {
philpem@5 13626 switch (interpolation) {
philpem@5 13627 case 2 : {
philpem@5 13628 cimg_forXY(dest,x,y)
philpem@5 13629 cimg_forZV(*this,z,v)
philpem@5 13630 dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
philpem@5 13631 } break;
philpem@5 13632 case 1 : {
philpem@5 13633 cimg_forXY(dest,x,y)
philpem@5 13634 cimg_forZV(*this,z,v)
philpem@5 13635 dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v,0);
philpem@5 13636 } break;
philpem@5 13637 default : {
philpem@5 13638 cimg_forXY(dest,x,y)
philpem@5 13639 cimg_forZV(*this,z,v)
philpem@5 13640 dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0);
philpem@5 13641 }
philpem@5 13642 }
philpem@5 13643 } break;
philpem@5 13644 case 1 : {
philpem@5 13645 switch (interpolation) {
philpem@5 13646 case 2 : {
philpem@5 13647 cimg_forXY(dest,x,y)
philpem@5 13648 cimg_forZV(*this,z,v)
philpem@5 13649 dest(x,y,z,v) = (T)cubic_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
philpem@5 13650 } break;
philpem@5 13651 case 1 : {
philpem@5 13652 cimg_forXY(dest,x,y)
philpem@5 13653 cimg_forZV(*this,z,v)
philpem@5 13654 dest(x,y,z,v) = (T)linear_atXY(cx + (x-cx)*ca + (y-cy)*sa,cy - (x-cx)*sa + (y-cy)*ca,z,v);
philpem@5 13655 } break;
philpem@5 13656 default : {
philpem@5 13657 cimg_forXY(dest,x,y)
philpem@5 13658 cimg_forZV(*this,z,v)
philpem@5 13659 dest(x,y,z,v) = atXY((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v);
philpem@5 13660 }
philpem@5 13661 }
philpem@5 13662 } break;
philpem@5 13663 case 2 : {
philpem@5 13664 switch (interpolation) {
philpem@5 13665 case 2 : {
philpem@5 13666 cimg_forXY(dest,x,y)
philpem@5 13667 cimg_forZV(*this,z,v)
philpem@5 13668 dest(x,y,z,v) = (T)cubic_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
philpem@5 13669 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
philpem@5 13670 } break;
philpem@5 13671 case 1 : {
philpem@5 13672 cimg_forXY(dest,x,y)
philpem@5 13673 cimg_forZV(*this,z,v)
philpem@5 13674 dest(x,y,z,v) = (T)linear_atXY(cimg::mod(cx + (x-cx)*ca + (y-cy)*sa,(float)dimx()),
philpem@5 13675 cimg::mod(cy - (x-cx)*sa + (y-cy)*ca,(float)dimy()),z,v);
philpem@5 13676 } break;
philpem@5 13677 default : {
philpem@5 13678 cimg_forXY(dest,x,y)
philpem@5 13679 cimg_forZV(*this,z,v)
philpem@5 13680 dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),dimx()),
philpem@5 13681 cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),dimy()),z,v);
philpem@5 13682 }
philpem@5 13683 }
philpem@5 13684 } break;
philpem@5 13685 default :
philpem@5 13686 throw CImgArgumentException("CImg<%s>::get_rotate() : Incorrect border conditions %d (should be 0,1 or 2).",
philpem@5 13687 pixel_type(),border_conditions);
philpem@5 13688 }
philpem@5 13689 }
philpem@5 13690 return dest;
philpem@5 13691 }
philpem@5 13692
philpem@5 13693 //! Resize an image.
philpem@5 13694 /**
philpem@5 13695 \param pdx Number of columns (new size along the X-axis).
philpem@5 13696 \param pdy Number of rows (new size along the Y-axis).
philpem@5 13697 \param pdz Number of slices (new size along the Z-axis).
philpem@5 13698 \param pdv Number of vector-channels (new size along the V-axis).
philpem@5 13699 \param interpolation_type Method of interpolation :
philpem@5 13700 - -1 = no interpolation : raw memory resizing.
philpem@5 13701 - 0 = no interpolation : additional space is filled according to \p border_condition.
philpem@5 13702 - 1 = bloc interpolation (nearest point).
philpem@5 13703 - 2 = moving average interpolation.
philpem@5 13704 - 3 = linear interpolation.
philpem@5 13705 - 4 = grid interpolation.
philpem@5 13706 - 5 = bi-cubic interpolation.
philpem@5 13707 \param border_condition Border condition type.
philpem@5 13708 \param center Set centering type (only if \p interpolation_type=0).
philpem@5 13709 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
philpem@5 13710 **/
philpem@5 13711 CImg<T>& resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
philpem@5 13712 const int interpolation_type=1, const int border_condition=-1, const bool center=false) {
philpem@5 13713 if (!pdx || !pdy || !pdz || !pdv) return assign();
philpem@5 13714 const unsigned int
philpem@5 13715 tdx = pdx<0?-pdx*width/100:pdx,
philpem@5 13716 tdy = pdy<0?-pdy*height/100:pdy,
philpem@5 13717 tdz = pdz<0?-pdz*depth/100:pdz,
philpem@5 13718 tdv = pdv<0?-pdv*dim/100:pdv,
philpem@5 13719 dx = tdx?tdx:1,
philpem@5 13720 dy = tdy?tdy:1,
philpem@5 13721 dz = tdz?tdz:1,
philpem@5 13722 dv = tdv?tdv:1;
philpem@5 13723 if (width==dx && height==dy && depth==dz && dim==dv) return *this;
philpem@5 13724 if (interpolation_type==-1 && dx*dy*dz*dv==size()) {
philpem@5 13725 width = dx; height = dy; depth = dz; dim = dv;
philpem@5 13726 return *this;
philpem@5 13727 }
philpem@5 13728 return get_resize(dx,dy,dz,dv,interpolation_type,border_condition,center).transfer_to(*this);
philpem@5 13729 }
philpem@5 13730
philpem@5 13731 CImg<T> get_resize(const int pdx, const int pdy=-100, const int pdz=-100, const int pdv=-100,
philpem@5 13732 const int interpolation_type=1, const int border_condition=-1, const bool center=false) const {
philpem@5 13733 if (!pdx || !pdy || !pdz || !pdv) return CImg<T>();
philpem@5 13734 const unsigned int
philpem@5 13735 tdx = pdx<0?-pdx*width/100:pdx,
philpem@5 13736 tdy = pdy<0?-pdy*height/100:pdy,
philpem@5 13737 tdz = pdz<0?-pdz*depth/100:pdz,
philpem@5 13738 tdv = pdv<0?-pdv*dim/100:pdv,
philpem@5 13739 dx = tdx?tdx:1,
philpem@5 13740 dy = tdy?tdy:1,
philpem@5 13741 dz = tdz?tdz:1,
philpem@5 13742 dv = tdv?tdv:1;
philpem@5 13743 if (width==dx && height==dy && depth==dz && dim==dv) return +*this;
philpem@5 13744 if (is_empty()) return CImg<T>(dx,dy,dz,dv,0);
philpem@5 13745
philpem@5 13746 CImg<T> res;
philpem@5 13747
philpem@5 13748 switch (interpolation_type) {
philpem@5 13749 case -1 : // Raw resizing
philpem@5 13750 cimg_std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv));
philpem@5 13751 break;
philpem@5 13752
philpem@5 13753 case 0 : { // No interpolation
philpem@5 13754 const unsigned int bx = width-1, by = height-1, bz = depth-1, bv = dim-1;
philpem@5 13755 res.assign(dx,dy,dz,dv);
philpem@5 13756 switch (border_condition) {
philpem@5 13757 case 1 : {
philpem@5 13758 if (center) {
philpem@5 13759 const int
philpem@5 13760 x0 = (res.dimx()-dimx())/2,
philpem@5 13761 y0 = (res.dimy()-dimy())/2,
philpem@5 13762 z0 = (res.dimz()-dimz())/2,
philpem@5 13763 v0 = (res.dimv()-dimv())/2,
philpem@5 13764 x1 = x0 + (int)bx,
philpem@5 13765 y1 = y0 + (int)by,
philpem@5 13766 z1 = z0 + (int)bz,
philpem@5 13767 v1 = v0 + (int)bv;
philpem@5 13768 res.draw_image(x0,y0,z0,v0,*this);
philpem@5 13769 cimg_for_outXYZV(res,x0,y0,z0,v0,x1,y1,z1,v1,x,y,z,v) res(x,y,z,v) = _atXYZV(x-x0,y-y0,z-z0,v-v0);
philpem@5 13770 } else {
philpem@5 13771 res.draw_image(*this);
philpem@5 13772 cimg_for_outXYZV(res,0,0,0,0,bx,by,bz,bv,x,y,z,v) res(x,y,z,v) = _atXYZV(x,y,z,v);
philpem@5 13773 }
philpem@5 13774 } break;
philpem@5 13775 case 2 : {
philpem@5 13776 int nx0 = 0, ny0 = 0, nz0 = 0, nv0 = 0;
philpem@5 13777 if (center) {
philpem@5 13778 const int
philpem@5 13779 x0 = (res.dimx()-dimx())/2,
philpem@5 13780 y0 = (res.dimy()-dimy())/2,
philpem@5 13781 z0 = (res.dimz()-dimz())/2,
philpem@5 13782 v0 = (res.dimv()-dimv())/2;
philpem@5 13783 nx0 = x0>0?x0-(1+x0/width)*width:x0;
philpem@5 13784 ny0 = y0>0?y0-(1+y0/height)*height:y0;
philpem@5 13785 nz0 = z0>0?z0-(1+z0/depth)*depth:z0;
philpem@5 13786 nv0 = v0>0?v0-(1+v0/dim)*dim:v0;
philpem@5 13787 }
philpem@5 13788 for (int k = nv0; k<(int)dv; k+=dimv())
philpem@5 13789 for (int z = nz0; z<(int)dz; z+=dimz())
philpem@5 13790 for (int y = ny0; y<(int)dy; y+=dimy())
philpem@5 13791 for (int x = nx0; x<(int)dx; x+=dimx()) res.draw_image(x,y,z,k,*this);
philpem@5 13792 } break;
philpem@5 13793 default : {
philpem@5 13794 res.fill(0);
philpem@5 13795 if (center) res.draw_image((res.dimx()-dimx())/2,(res.dimy()-dimy())/2,(res.dimz()-dimz())/2,(res.dimv()-dimv())/2,*this);
philpem@5 13796 else res.draw_image(*this);
philpem@5 13797 }
philpem@5 13798 }
philpem@5 13799 } break;
philpem@5 13800
philpem@5 13801 case 1 : { // Nearest-neighbor interpolation
philpem@5 13802 res.assign(dx,dy,dz,dv);
philpem@5 13803 unsigned int
philpem@5 13804 *const offx = new unsigned int[dx],
philpem@5 13805 *const offy = new unsigned int[dy+1],
philpem@5 13806 *const offz = new unsigned int[dz+1],
philpem@5 13807 *const offv = new unsigned int[dv+1],
philpem@5 13808 *poffx, *poffy, *poffz, *poffv,
philpem@5 13809 curr, old;
philpem@5 13810 const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz;
philpem@5 13811 poffx = offx; curr = 0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }}
philpem@5 13812 poffy = offy; curr = 0; { cimg_forY(res,y) { old=curr; curr=(y+1)*height/dy; *(poffy++) = width*((unsigned int)curr-(unsigned int)old); }} *poffy=0;
philpem@5 13813 poffz = offz; curr = 0; { cimg_forZ(res,z) { old=curr; curr=(z+1)*depth/dz; *(poffz++) = wh*((unsigned int)curr-(unsigned int)old); }} *poffz=0;
philpem@5 13814 poffv = offv; curr = 0; { cimg_forV(res,k) { old=curr; curr=(k+1)*dim/dv; *(poffv++) = whd*((unsigned int)curr-(unsigned int)old); }} *poffv=0;
philpem@5 13815 T *ptrd = res.data;
philpem@5 13816 const T* ptrv = data;
philpem@5 13817 poffv = offv;
philpem@5 13818 for (unsigned int k=0; k<dv; ) {
philpem@5 13819 const T *ptrz = ptrv;
philpem@5 13820 poffz = offz;
philpem@5 13821 for (unsigned int z=0; z<dz; ) {
philpem@5 13822 const T *ptry = ptrz;
philpem@5 13823 poffy = offy;
philpem@5 13824 for (unsigned int y=0; y<dy; ) {
philpem@5 13825 const T *ptrx = ptry;
philpem@5 13826 poffx = offx;
philpem@5 13827 cimg_forX(res,x) { *(ptrd++) = *ptrx; ptrx+=*(poffx++); }
philpem@5 13828 ++y;
philpem@5 13829 unsigned int dy = *(poffy++);
philpem@5 13830 for (;!dy && y<dy; cimg_std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), ++y, ptrd+=dx, dy=*(poffy++)) {}
philpem@5 13831 ptry+=dy;
philpem@5 13832 }
philpem@5 13833 ++z;
philpem@5 13834 unsigned int dz = *(poffz++);
philpem@5 13835 for (;!dz && z<dz; cimg_std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), ++z, ptrd+=rwh, dz=*(poffz++)) {}
philpem@5 13836 ptrz+=dz;
philpem@5 13837 }
philpem@5 13838 ++k;
philpem@5 13839 unsigned int dv = *(poffv++);
philpem@5 13840 for (;!dv && k<dv; cimg_std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), ++k, ptrd+=rwhd, dv=*(poffv++)) {}
philpem@5 13841 ptrv+=dv;
philpem@5 13842 }
philpem@5 13843 delete[] offx; delete[] offy; delete[] offz; delete[] offv;
philpem@5 13844 } break;
philpem@5 13845
philpem@5 13846 case 2 : { // Moving average
philpem@5 13847 bool instance_first = true;
philpem@5 13848 if (dx!=width) {
philpem@5 13849 CImg<Tfloat> tmp(dx,height,depth,dim,0);
philpem@5 13850 for (unsigned int a = width*dx, b = width, c = dx, s = 0, t = 0; a; ) {
philpem@5 13851 const unsigned int d = cimg::min(b,c);
philpem@5 13852 a-=d; b-=d; c-=d;
philpem@5 13853 cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d;
philpem@5 13854 if (!b) { cimg_forYZV(tmp,y,z,v) tmp(t,y,z,v)/=width; ++t; b = width; }
philpem@5 13855 if (!c) { ++s; c = dx; }
philpem@5 13856 }
philpem@5 13857 tmp.transfer_to(res);
philpem@5 13858 instance_first = false;
philpem@5 13859 }
philpem@5 13860 if (dy!=height) {
philpem@5 13861 CImg<Tfloat> tmp(dx,dy,depth,dim,0);
philpem@5 13862 for (unsigned int a = height*dy, b = height, c = dy, s = 0, t = 0; a; ) {
philpem@5 13863 const unsigned int d = cimg::min(b,c);
philpem@5 13864 a-=d; b-=d; c-=d;
philpem@5 13865 if (instance_first) cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d;
philpem@5 13866 else cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d;
philpem@5 13867 if (!b) { cimg_forXZV(tmp,x,z,v) tmp(x,t,z,v)/=height; ++t; b = height; }
philpem@5 13868 if (!c) { ++s; c = dy; }
philpem@5 13869 }
philpem@5 13870 tmp.transfer_to(res);
philpem@5 13871 instance_first = false;
philpem@5 13872 }
philpem@5 13873 if (dz!=depth) {
philpem@5 13874 CImg<Tfloat> tmp(dx,dy,dz,dim,0);
philpem@5 13875 for (unsigned int a = depth*dz, b = depth, c = dz, s = 0, t = 0; a; ) {
philpem@5 13876 const unsigned int d = cimg::min(b,c);
philpem@5 13877 a-=d; b-=d; c-=d;
philpem@5 13878 if (instance_first) cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d;
philpem@5 13879 else cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d;
philpem@5 13880 if (!b) { cimg_forXYV(tmp,x,y,v) tmp(x,y,t,v)/=depth; ++t; b = depth; }
philpem@5 13881 if (!c) { ++s; c = dz; }
philpem@5 13882 }
philpem@5 13883 tmp.transfer_to(res);
philpem@5 13884 instance_first = false;
philpem@5 13885 }
philpem@5 13886 if (dv!=dim) {
philpem@5 13887 CImg<Tfloat> tmp(dx,dy,dz,dv,0);
philpem@5 13888 for (unsigned int a = dim*dv, b = dim, c = dv, s = 0, t = 0; a; ) {
philpem@5 13889 const unsigned int d = cimg::min(b,c);
philpem@5 13890 a-=d; b-=d; c-=d;
philpem@5 13891 if (instance_first) cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d;
philpem@5 13892 else cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d;
philpem@5 13893 if (!b) { cimg_forXYZ(tmp,x,y,z) tmp(x,y,z,t)/=dim; ++t; b = dim; }
philpem@5 13894 if (!c) { ++s; c = dv; }
philpem@5 13895 }
philpem@5 13896 tmp.transfer_to(res);
philpem@5 13897 instance_first = false;
philpem@5 13898 }
philpem@5 13899 } break;
philpem@5 13900
philpem@5 13901 case 3 : { // Linear interpolation
philpem@5 13902 const unsigned int dimmax = cimg::max(dx,dy,dz,dv);
philpem@5 13903 const float
philpem@5 13904 sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
philpem@5 13905 sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
philpem@5 13906 sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
philpem@5 13907 sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
philpem@5 13908
philpem@5 13909 unsigned int *const off = new unsigned int[dimmax], *poff;
philpem@5 13910 float *const foff = new float[dimmax], *pfoff, old, curr;
philpem@5 13911 CImg<T> resx, resy, resz, resv;
philpem@5 13912 T *ptrd;
philpem@5 13913
philpem@5 13914 if (dx!=width) {
philpem@5 13915 if (width==1) resx = get_resize(dx,height,depth,dim,1,0);
philpem@5 13916 else {
philpem@5 13917 resx.assign(dx,height,depth,dim);
philpem@5 13918 curr = old = 0; poff = off; pfoff = foff;
philpem@5 13919 cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; }
philpem@5 13920 ptrd = resx.data;
philpem@5 13921 const T *ptrs0 = data;
philpem@5 13922 cimg_forYZV(resx,y,z,k) {
philpem@5 13923 poff = off; pfoff = foff;
philpem@5 13924 const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1);
philpem@5 13925 cimg_forX(resx,x) {
philpem@5 13926 const float alpha = *(pfoff++);
philpem@5 13927 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:(T)0);
philpem@5 13928 *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2);
philpem@5 13929 ptrs+=*(poff++);
philpem@5 13930 }
philpem@5 13931 ptrs0+=width;
philpem@5 13932 }
philpem@5 13933 }
philpem@5 13934 } else resx.assign(*this,true);
philpem@5 13935
philpem@5 13936 if (dy!=height) {
philpem@5 13937 if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0);
philpem@5 13938 else {
philpem@5 13939 resy.assign(dx,dy,depth,dim);
philpem@5 13940 curr = old = 0; poff = off; pfoff = foff;
philpem@5 13941 cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); }
philpem@5 13942 cimg_forXZV(resy,x,z,k) {
philpem@5 13943 ptrd = resy.ptr(x,0,z,k);
philpem@5 13944 const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx;
philpem@5 13945 poff = off; pfoff = foff;
philpem@5 13946 cimg_forY(resy,y) {
philpem@5 13947 const float alpha = *(pfoff++);
philpem@5 13948 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:(T)0);
philpem@5 13949 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
philpem@5 13950 ptrd+=dx;
philpem@5 13951 ptrs+=*(poff++);
philpem@5 13952 }
philpem@5 13953 }
philpem@5 13954 }
philpem@5 13955 resx.assign();
philpem@5 13956 } else resy.assign(resx,true);
philpem@5 13957
philpem@5 13958 if (dz!=depth) {
philpem@5 13959 if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0);
philpem@5 13960 else {
philpem@5 13961 const unsigned int wh = dx*dy;
philpem@5 13962 resz.assign(dx,dy,dz,dim);
philpem@5 13963 curr = old = 0; poff = off; pfoff = foff;
philpem@5 13964 cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); }
philpem@5 13965 cimg_forXYV(resz,x,y,k) {
philpem@5 13966 ptrd = resz.ptr(x,y,0,k);
philpem@5 13967 const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh;
philpem@5 13968 poff = off; pfoff = foff;
philpem@5 13969 cimg_forZ(resz,z) {
philpem@5 13970 const float alpha = *(pfoff++);
philpem@5 13971 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:(T)0);
philpem@5 13972 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
philpem@5 13973 ptrd+=wh;
philpem@5 13974 ptrs+=*(poff++);
philpem@5 13975 }
philpem@5 13976 }
philpem@5 13977 }
philpem@5 13978 resy.assign();
philpem@5 13979 } else resz.assign(resy,true);
philpem@5 13980
philpem@5 13981 if (dv!=dim) {
philpem@5 13982 if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0);
philpem@5 13983 else {
philpem@5 13984 const unsigned int whd = dx*dy*dz;
philpem@5 13985 resv.assign(dx,dy,dz,dv);
philpem@5 13986 curr = old = 0; poff = off; pfoff = foff;
philpem@5 13987 cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); }
philpem@5 13988 cimg_forXYZ(resv,x,y,z) {
philpem@5 13989 ptrd = resv.ptr(x,y,z,0);
philpem@5 13990 const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd;
philpem@5 13991 poff = off; pfoff = foff;
philpem@5 13992 cimg_forV(resv,k) {
philpem@5 13993 const float alpha = *(pfoff++);
philpem@5 13994 const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:(T)0);
philpem@5 13995 *ptrd = (T)((1-alpha)*val1 + alpha*val2);
philpem@5 13996 ptrd+=whd;
philpem@5 13997 ptrs+=*(poff++);
philpem@5 13998 }
philpem@5 13999 }
philpem@5 14000 }
philpem@5 14001 resz.assign();
philpem@5 14002 } else resv.assign(resz,true);
philpem@5 14003
philpem@5 14004 delete[] off; delete[] foff;
philpem@5 14005 return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv;
philpem@5 14006 } break;
philpem@5 14007
philpem@5 14008 case 4 : { // Grid filling
philpem@5 14009 res.assign(dx,dy,dz,dv,0);
philpem@5 14010 cimg_forXYZV(*this,x,y,z,k) res(x*dx/width,y*dy/height,z*dz/depth,k*dv/dim) = (*this)(x,y,z,k);
philpem@5 14011 } break;
philpem@5 14012
philpem@5 14013 case 5 : { // Cubic interpolation
philpem@5 14014 const float
philpem@5 14015 sx = (border_condition<0 && dx>width )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx,
philpem@5 14016 sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy,
philpem@5 14017 sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz,
philpem@5 14018 sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv;
philpem@5 14019 res.assign(dx,dy,dz,dv);
philpem@5 14020 T *ptrd = res.ptr();
philpem@5 14021 float cx, cy, cz, ck = 0;
philpem@5 14022 cimg_forV(res,k) { cz = 0;
philpem@5 14023 cimg_forZ(res,z) { cy = 0;
philpem@5 14024 cimg_forY(res,y) { cx = 0;
philpem@5 14025 cimg_forX(res,x) {
philpem@5 14026 *(ptrd++) = (T)(border_condition?_cubic_atXY(cx,cy,(int)cz,(int)ck):cubic_atXY(cx,cy,(int)cz,(int)ck,0));
philpem@5 14027 cx+=sx;
philpem@5 14028 } cy+=sy;
philpem@5 14029 } cz+=sz;
philpem@5 14030 } ck+=sv;
philpem@5 14031 }
philpem@5 14032 } break;
philpem@5 14033
philpem@5 14034 default : // Invalid interpolation method
philpem@5 14035 throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation_type %d "
philpem@5 14036 "(should be { -1=raw, 0=zero, 1=nearest, 2=average, 3=linear, 4=grid, 5=bicubic}).",
philpem@5 14037 pixel_type(),interpolation_type);
philpem@5 14038 }
philpem@5 14039 return res;
philpem@5 14040 }
philpem@5 14041
philpem@5 14042 //! Resize an image.
philpem@5 14043 /**
philpem@5 14044 \param src Image giving the geometry of the resize.
philpem@5 14045 \param interpolation_type Interpolation method :
philpem@5 14046 - 1 = raw memory
philpem@5 14047 - 0 = no interpolation : additional space is filled with 0.
philpem@5 14048 - 1 = bloc interpolation (nearest point).
philpem@5 14049 - 2 = mosaic : image is repeated if necessary.
philpem@5 14050 - 3 = linear interpolation.
philpem@5 14051 - 4 = grid interpolation.
philpem@5 14052 - 5 = bi-cubic interpolation.
philpem@5 14053 \param border_condition Border condition type.
philpem@5 14054 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
philpem@5 14055 **/
philpem@5 14056 template<typename t>
philpem@5 14057 CImg<T>& resize(const CImg<t>& src, const int interpolation_type=1,
philpem@5 14058 const int border_condition=-1, const bool center=false) {
philpem@5 14059 return resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
philpem@5 14060 }
philpem@5 14061
philpem@5 14062 template<typename t>
philpem@5 14063 CImg<T> get_resize(const CImg<t>& src, const int interpolation_type=1,
philpem@5 14064 const int border_condition=-1, const bool center=false) const {
philpem@5 14065 return get_resize(src.width,src.height,src.depth,src.dim,interpolation_type,border_condition,center);
philpem@5 14066 }
philpem@5 14067
philpem@5 14068 //! Resize an image.
philpem@5 14069 /**
philpem@5 14070 \param disp = Display giving the geometry of the resize.
philpem@5 14071 \param interpolation_type = Resizing type :
philpem@5 14072 - 0 = no interpolation : additional space is filled with 0.
philpem@5 14073 - 1 = bloc interpolation (nearest point).
philpem@5 14074 - 2 = mosaic : image is repeated if necessary.
philpem@5 14075 - 3 = linear interpolation.
philpem@5 14076 - 4 = grid interpolation.
philpem@5 14077 - 5 = bi-cubic interpolation.
philpem@5 14078 - 6 = moving average (best quality for photographs)
philpem@5 14079 \param border_condition Border condition type.
philpem@5 14080 \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100).
philpem@5 14081 **/
philpem@5 14082 CImg<T>& resize(const CImgDisplay& disp, const int interpolation_type=1,
philpem@5 14083 const int border_condition=-1, const bool center=false) {
philpem@5 14084 return resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
philpem@5 14085 }
philpem@5 14086
philpem@5 14087 CImg<T> get_resize(const CImgDisplay& disp, const int interpolation_type=1,
philpem@5 14088 const int border_condition=-1, const bool center=false) const {
philpem@5 14089 return get_resize(disp.width,disp.height,depth,dim,interpolation_type,border_condition,center);
philpem@5 14090 }
philpem@5 14091
philpem@5 14092 //! Half-resize an image, using a special optimized filter.
philpem@5 14093 CImg<T>& resize_halfXY() {
philpem@5 14094 return get_resize_halfXY().transfer_to(*this);
philpem@5 14095 }
philpem@5 14096
philpem@5 14097 CImg<T> get_resize_halfXY() const {
philpem@5 14098 if (is_empty()) return *this;
philpem@5 14099 const Tfloat mask[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f,
philpem@5 14100 0.1231940459f, 0.1935127547f, 0.1231940459f,
philpem@5 14101 0.07842776544f, 0.1231940459f, 0.07842776544f };
philpem@5 14102 T I[9] = { 0 };
philpem@5 14103 CImg<T> dest(width/2,height/2,depth,dim);
philpem@5 14104 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I)
philpem@5 14105 if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)
philpem@5 14106 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
philpem@5 14107 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
philpem@5 14108 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
philpem@5 14109 return dest;
philpem@5 14110 }
philpem@5 14111
philpem@5 14112 //! Upscale an image by a factor 2x.
philpem@5 14113 /**
philpem@5 14114 Use anisotropic upscaling algorithm described at
philpem@5 14115 http://scale2x.sourceforge.net/algorithm.html
philpem@5 14116 **/
philpem@5 14117 CImg<T>& resize_doubleXY() {
philpem@5 14118 return get_resize_doubleXY().transfer_to(*this);
philpem@5 14119 }
philpem@5 14120
philpem@5 14121 CImg<T> get_resize_doubleXY() const {
philpem@5 14122 #define _cimg_gs2x_for3(bound,i) \
philpem@5 14123 for (int i = 0, _p1##i = 0, \
philpem@5 14124 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
philpem@5 14125 _n1##i<(int)(bound) || i==--_n1##i; \
philpem@5 14126 _p1##i = i++, ++_n1##i, ptrd1+=(res).width, ptrd2+=(res).width)
philpem@5 14127
philpem@5 14128 #define _cimg_gs2x_for3x3(img,x,y,z,v,I) \
philpem@5 14129 _cimg_gs2x_for3((img).height,y) for (int x = 0, \
philpem@5 14130 _p1##x = 0, \
philpem@5 14131 _n1##x = (int)( \
philpem@5 14132 (I[1] = (img)(0,_p1##y,z,v)), \
philpem@5 14133 (I[3] = I[4] = (img)(0,y,z,v)), \
philpem@5 14134 (I[7] = (img)(0,_n1##y,z,v)), \
philpem@5 14135 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 14136 (_n1##x<(int)((img).width) && ( \
philpem@5 14137 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 14138 (I[5] = (img)(_n1##x,y,z,v)), \
philpem@5 14139 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 14140 x==--_n1##x; \
philpem@5 14141 I[1] = I[2], \
philpem@5 14142 I[3] = I[4], I[4] = I[5], \
philpem@5 14143 I[7] = I[8], \
philpem@5 14144 _p1##x = x++, ++_n1##x)
philpem@5 14145
philpem@5 14146 if (is_empty()) return *this;
philpem@5 14147 CImg<T> res(2*width,2*height,depth,dim);
philpem@5 14148 CImg_3x3(I,T);
philpem@5 14149 cimg_forZV(*this,z,k) {
philpem@5 14150 T
philpem@5 14151 *ptrd1 = res.ptr(0,0,0,k),
philpem@5 14152 *ptrd2 = ptrd1 + res.width;
philpem@5 14153 _cimg_gs2x_for3x3(*this,x,y,0,k,I) {
philpem@5 14154 if (Icp!=Icn && Ipc!=Inc) {
philpem@5 14155 *(ptrd1++) = Ipc==Icp?Ipc:Icc;
philpem@5 14156 *(ptrd1++) = Icp==Inc?Inc:Icc;
philpem@5 14157 *(ptrd2++) = Ipc==Icn?Ipc:Icc;
philpem@5 14158 *(ptrd2++) = Icn==Inc?Inc:Icc;
philpem@5 14159 } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; }
philpem@5 14160 }
philpem@5 14161 }
philpem@5 14162 return res;
philpem@5 14163 }
philpem@5 14164
philpem@5 14165 //! Upscale an image by a factor 3x.
philpem@5 14166 /**
philpem@5 14167 Use anisotropic upscaling algorithm described at
philpem@5 14168 http://scale2x.sourceforge.net/algorithm.html
philpem@5 14169 **/
philpem@5 14170 CImg<T>& resize_tripleXY() {
philpem@5 14171 return get_resize_tripleXY().transfer_to(*this);
philpem@5 14172 }
philpem@5 14173
philpem@5 14174 CImg<T> get_resize_tripleXY() const {
philpem@5 14175 #define _cimg_gs3x_for3(bound,i) \
philpem@5 14176 for (int i = 0, _p1##i = 0, \
philpem@5 14177 _n1##i = 1>=(bound)?(int)(bound)-1:1; \
philpem@5 14178 _n1##i<(int)(bound) || i==--_n1##i; \
philpem@5 14179 _p1##i = i++, ++_n1##i, ptrd1+=2*(res).width, ptrd2+=2*(res).width, ptrd3+=2*(res).width)
philpem@5 14180
philpem@5 14181 #define _cimg_gs3x_for3x3(img,x,y,z,v,I) \
philpem@5 14182 _cimg_gs3x_for3((img).height,y) for (int x = 0, \
philpem@5 14183 _p1##x = 0, \
philpem@5 14184 _n1##x = (int)( \
philpem@5 14185 (I[0] = I[1] = (img)(0,_p1##y,z,v)), \
philpem@5 14186 (I[3] = I[4] = (img)(0,y,z,v)), \
philpem@5 14187 (I[6] = I[7] = (img)(0,_n1##y,z,v)), \
philpem@5 14188 1>=(img).width?(int)((img).width)-1:1); \
philpem@5 14189 (_n1##x<(int)((img).width) && ( \
philpem@5 14190 (I[2] = (img)(_n1##x,_p1##y,z,v)), \
philpem@5 14191 (I[5] = (img)(_n1##x,y,z,v)), \
philpem@5 14192 (I[8] = (img)(_n1##x,_n1##y,z,v)),1)) || \
philpem@5 14193 x==--_n1##x; \
philpem@5 14194 I[0] = I[1], I[1] = I[2], \
philpem@5 14195 I[3] = I[4], I[4] = I[5], \
philpem@5 14196 I[6] = I[7], I[7] = I[8], \
philpem@5 14197 _p1##x = x++, ++_n1##x)
philpem@5 14198
philpem@5 14199 if (is_empty()) return *this;
philpem@5 14200 CImg<T> res(3*width,3*height,depth,dim);
philpem@5 14201 CImg_3x3(I,T);
philpem@5 14202 cimg_forZV(*this,z,k) {
philpem@5 14203 T
philpem@5 14204 *ptrd1 = res.ptr(0,0,0,k),
philpem@5 14205 *ptrd2 = ptrd1 + res.width,
philpem@5 14206 *ptrd3 = ptrd2 + res.width;
philpem@5 14207 _cimg_gs3x_for3x3(*this,x,y,0,k,I) {
philpem@5 14208 if (Icp != Icn && Ipc != Inc) {
philpem@5 14209 *(ptrd1++) = Ipc==Icp?Ipc:Icc;
philpem@5 14210 *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc;
philpem@5 14211 *(ptrd1++) = Icp==Inc?Inc:Icc;
philpem@5 14212 *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc;
philpem@5 14213 *(ptrd2++) = Icc;
philpem@5 14214 *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc;
philpem@5 14215 *(ptrd3++) = Ipc==Icn?Ipc:Icc;
philpem@5 14216 *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc;
philpem@5 14217 *(ptrd3++) = Icn==Inc?Inc:Icc;
philpem@5 14218 } else {
philpem@5 14219 *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc;
philpem@5 14220 *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc;
philpem@5 14221 *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc;
philpem@5 14222 }
philpem@5 14223 }
philpem@5 14224 }
philpem@5 14225 return res;
philpem@5 14226 }
philpem@5 14227
philpem@5 14228 // Warp an image.
philpem@5 14229 template<typename t>
philpem@5 14230 CImg<T>& warp(const CImg<t>& warp, const bool relative=false,
philpem@5 14231 const bool interpolation=true, const unsigned int border_conditions=0) {
philpem@5 14232 return get_warp(warp,relative,interpolation,border_conditions).transfer_to(*this);
philpem@5 14233 }
philpem@5 14234
philpem@5 14235 template<typename t>
philpem@5 14236 CImg<T> get_warp(const CImg<t>& warp, const bool relative=false,
philpem@5 14237 const bool interpolation=true, const unsigned int border_conditions=0) const {
philpem@5 14238 if (is_empty() || !warp) return *this;
philpem@5 14239 if (!is_sameXYZ(warp))
philpem@5 14240 throw CImgArgumentException("CImg<%s>::warp() : Instance image (%u,%u,%u,%u,%p) and warping field (%u,%u,%u,%u,%p) "
philpem@5 14241 "have different XYZ dimensions.",
philpem@5 14242 pixel_type(),width,height,depth,dim,data,
philpem@5 14243 warp.width,warp.height,warp.depth,warp.dim,warp.data);
philpem@5 14244 CImg<T> res(width,height,depth,dim);
philpem@5 14245 switch (warp.dim) {
philpem@5 14246 case 1 : // 1D warping.
philpem@5 14247 if (relative) { // Relative warp coordinates
philpem@5 14248 if (interpolation) switch (border_conditions) {
philpem@5 14249 case 2 : {
philpem@5 14250 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14251 res(x,y,z,v) = (T)_linear_atX(cimg::mod(x-(float)warp(x,y,z,0),(float)width),y,z,v);
philpem@5 14252 } break;
philpem@5 14253 case 1 : {
philpem@5 14254 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14255 res(x,y,z,v) = (T)_linear_atX(x-(float)warp(x,y,z,0),y,z,v);
philpem@5 14256 } break;
philpem@5 14257 default : {
philpem@5 14258 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14259 res(x,y,z,v) = (T)linear_atX(x-(float)warp(x,y,z,0),y,z,v,0);
philpem@5 14260 }
philpem@5 14261 } else switch (border_conditions) {
philpem@5 14262 case 2 : {
philpem@5 14263 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14264 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),y,z,v);
philpem@5 14265 } break;
philpem@5 14266 case 1 : {
philpem@5 14267 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14268 res(x,y,z,v) = _atX(x-(int)warp(x,y,z,0),y,z,v);
philpem@5 14269 } break;
philpem@5 14270 default : {
philpem@5 14271 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14272 res(x,y,z,v) = atX(x-(int)warp(x,y,z,0),y,z,v,0);
philpem@5 14273 }
philpem@5 14274 }
philpem@5 14275 } else { // Absolute warp coordinates
philpem@5 14276 if (interpolation) switch (border_conditions) {
philpem@5 14277 case 2 : {
philpem@5 14278 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14279 res(x,y,z,v) = (T)_linear_atX(cimg::mod((float)warp(x,y,z,0),(float)width),y,z,v);
philpem@5 14280 } break;
philpem@5 14281 case 1 : {
philpem@5 14282 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14283 res(x,y,z,v) = (T)_linear_atX((float)warp(x,y,z,0),y,z,v);
philpem@5 14284 } break;
philpem@5 14285 default : {
philpem@5 14286 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14287 res(x,y,z,v) = (T)linear_atX((float)warp(x,y,z,0),y,z,v,0);
philpem@5 14288 }
philpem@5 14289 } else switch (border_conditions) {
philpem@5 14290 case 2 : {
philpem@5 14291 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14292 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),y,z,v);
philpem@5 14293 } break;
philpem@5 14294 case 1 : {
philpem@5 14295 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14296 res(x,y,z,v) = _atX((int)warp(x,y,z,0),y,z,v);
philpem@5 14297 } break;
philpem@5 14298 default : {
philpem@5 14299 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14300 res(x,y,z,v) = atX((int)warp(x,y,z,0),y,z,v,0);
philpem@5 14301 }
philpem@5 14302 }
philpem@5 14303 }
philpem@5 14304 break;
philpem@5 14305
philpem@5 14306 case 2 : // 2D warping
philpem@5 14307 if (relative) { // Relative warp coordinates
philpem@5 14308 if (interpolation) switch (border_conditions) {
philpem@5 14309 case 2 : {
philpem@5 14310 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14311 res(x,y,z,v) = (T)_linear_atXY(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
philpem@5 14312 cimg::mod(y-(float)warp(x,y,z,1),(float)height),z,v);
philpem@5 14313 } break;
philpem@5 14314 case 1 : {
philpem@5 14315 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14316 res(x,y,z,v) = (T)_linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v);
philpem@5 14317 } break;
philpem@5 14318 default : {
philpem@5 14319 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14320 res(x,y,z,v) = (T)linear_atXY(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z,v,0);
philpem@5 14321 }
philpem@5 14322 } else switch (border_conditions) {
philpem@5 14323 case 2 : {
philpem@5 14324 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14325 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
philpem@5 14326 cimg::mod(y-(int)warp(x,y,z,1),(int)height),z,v);
philpem@5 14327 } break;
philpem@5 14328 case 1 : {
philpem@5 14329 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14330 res(x,y,z,v) = _atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v);
philpem@5 14331 } break;
philpem@5 14332 default : {
philpem@5 14333 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14334 res(x,y,z,v) = atXY(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z,v,0);
philpem@5 14335 }
philpem@5 14336 }
philpem@5 14337 } else { // Absolute warp coordinates
philpem@5 14338 if (interpolation) switch (border_conditions) {
philpem@5 14339 case 2 : {
philpem@5 14340 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14341 res(x,y,z,v) = (T)_linear_atXY(cimg::mod((float)warp(x,y,z,0),(float)width),
philpem@5 14342 cimg::mod((float)warp(x,y,z,1),(float)height),z,v);
philpem@5 14343 } break;
philpem@5 14344 case 1 : {
philpem@5 14345 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14346 res(x,y,z,v) = (T)_linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v);
philpem@5 14347 } break;
philpem@5 14348 default : {
philpem@5 14349 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14350 res(x,y,z,v) = (T)linear_atXY((float)warp(x,y,z,0),(float)warp(x,y,z,1),z,v,0);
philpem@5 14351 }
philpem@5 14352 } else switch (border_conditions) {
philpem@5 14353 case 2 : {
philpem@5 14354 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14355 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
philpem@5 14356 cimg::mod((int)warp(x,y,z,1),(int)depth),z,v);
philpem@5 14357 } break;
philpem@5 14358 case 1 : {
philpem@5 14359 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14360 res(x,y,z,v) = _atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v);
philpem@5 14361 } break;
philpem@5 14362 default : {
philpem@5 14363 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14364 res(x,y,z,v) = atXY((int)warp(x,y,z,0),(int)warp(x,y,z,1),z,v,0);
philpem@5 14365 }
philpem@5 14366 }
philpem@5 14367 }
philpem@5 14368 break;
philpem@5 14369
philpem@5 14370 case 3 : // 3D warping
philpem@5 14371 if (relative) { // Relative warp coordinates
philpem@5 14372 if (interpolation) switch (border_conditions) {
philpem@5 14373 case 2 : {
philpem@5 14374 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14375 res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
philpem@5 14376 cimg::mod(y-(float)warp(x,y,z,1),(float)height),
philpem@5 14377 cimg::mod(z-(float)warp(x,y,z,2),(float)depth),v);
philpem@5 14378 } break;
philpem@5 14379 case 1 : {
philpem@5 14380 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14381 res(x,y,z,v) = (T)_linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v);
philpem@5 14382 } break;
philpem@5 14383 default : {
philpem@5 14384 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14385 res(x,y,z,v) = (T)linear_atXYZ(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v,0);
philpem@5 14386 }
philpem@5 14387 } else switch (border_conditions) {
philpem@5 14388 case 2 : {
philpem@5 14389 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14390 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
philpem@5 14391 cimg::mod(y-(int)warp(x,y,z,1),(int)height),
philpem@5 14392 cimg::mod(z-(int)warp(x,y,z,2),(int)depth),v);
philpem@5 14393 } break;
philpem@5 14394 case 1 : {
philpem@5 14395 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14396 res(x,y,z,v) = _atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v);
philpem@5 14397 } break;
philpem@5 14398 default : {
philpem@5 14399 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14400 res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v,0);
philpem@5 14401 }
philpem@5 14402 }
philpem@5 14403 } else { // Absolute warp coordinates
philpem@5 14404 if (interpolation) switch (border_conditions) {
philpem@5 14405 case 2 : {
philpem@5 14406 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14407 res(x,y,z,v) = (T)_linear_atXYZ(cimg::mod((float)warp(x,y,z,0),(float)width),
philpem@5 14408 cimg::mod((float)warp(x,y,z,1),(float)height),
philpem@5 14409 cimg::mod((float)warp(x,y,z,2),(float)depth),v);
philpem@5 14410 } break;
philpem@5 14411 case 1 : {
philpem@5 14412 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14413 res(x,y,z,v) = (T)_linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v);
philpem@5 14414 } break;
philpem@5 14415 default : {
philpem@5 14416 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14417 res(x,y,z,v) = (T)linear_atXYZ((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),v,0);
philpem@5 14418 }
philpem@5 14419 } else switch (border_conditions) {
philpem@5 14420 case 2 : {
philpem@5 14421 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14422 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
philpem@5 14423 cimg::mod((int)warp(x,y,z,1),(int)height),
philpem@5 14424 cimg::mod((int)warp(x,y,z,2),(int)depth),v);
philpem@5 14425 } break;
philpem@5 14426 case 1 : {
philpem@5 14427 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14428 res(x,y,z,v) = _atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v);
philpem@5 14429 } break;
philpem@5 14430 default : {
philpem@5 14431 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14432 res(x,y,z,v) = atXYZ((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),v,0);
philpem@5 14433 }
philpem@5 14434 }
philpem@5 14435 }
philpem@5 14436 break;
philpem@5 14437
philpem@5 14438 default : // 4D warping
philpem@5 14439 if (relative) { // Relative warp coordinates
philpem@5 14440 if (interpolation) switch (border_conditions) {
philpem@5 14441 case 2 : {
philpem@5 14442 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14443 res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod(x-(float)warp(x,y,z,0),(float)width),
philpem@5 14444 cimg::mod(y-(float)warp(x,y,z,1),(float)height),
philpem@5 14445 cimg::mod(z-(float)warp(x,y,z,2),(float)depth),
philpem@5 14446 cimg::mod(z-(float)warp(x,y,z,3),(float)dim));
philpem@5 14447 } break;
philpem@5 14448 case 1 : {
philpem@5 14449 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14450 res(x,y,z,v) = (T)_linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3));
philpem@5 14451 } break;
philpem@5 14452 default : {
philpem@5 14453 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14454 res(x,y,z,v) = (T)linear_atXYZV(x-(float)warp(x,y,z,0),y-(float)warp(x,y,z,1),z-(float)warp(x,y,z,2),v-(float)warp(x,y,z,3),0);
philpem@5 14455 }
philpem@5 14456 } else switch (border_conditions) {
philpem@5 14457 case 2 : {
philpem@5 14458 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14459 res(x,y,z,v) = (*this)(cimg::mod(x-(int)warp(x,y,z,0),(int)width),
philpem@5 14460 cimg::mod(y-(int)warp(x,y,z,1),(int)height),
philpem@5 14461 cimg::mod(z-(int)warp(x,y,z,2),(int)depth),
philpem@5 14462 cimg::mod(v-(int)warp(x,y,z,3),(int)dim));
philpem@5 14463 } break;
philpem@5 14464 case 1 : {
philpem@5 14465 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14466 res(x,y,z,v) = _atXYZV(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3));
philpem@5 14467 } break;
philpem@5 14468 default : {
philpem@5 14469 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14470 res(x,y,z,v) = atXYZ(x-(int)warp(x,y,z,0),y-(int)warp(x,y,z,1),z-(int)warp(x,y,z,2),v-(int)warp(x,y,z,3),0);
philpem@5 14471 }
philpem@5 14472 }
philpem@5 14473 } else { // Absolute warp coordinates
philpem@5 14474 if (interpolation) switch (border_conditions) {
philpem@5 14475 case 2 : {
philpem@5 14476 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14477 res(x,y,z,v) = (T)_linear_atXYZV(cimg::mod((float)warp(x,y,z,0),(float)width),
philpem@5 14478 cimg::mod((float)warp(x,y,z,1),(float)height),
philpem@5 14479 cimg::mod((float)warp(x,y,z,2),(float)depth),
philpem@5 14480 cimg::mod((float)warp(x,y,z,3),(float)dim));
philpem@5 14481 } break;
philpem@5 14482 case 1 : {
philpem@5 14483 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14484 res(x,y,z,v) = (T)_linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3));
philpem@5 14485 } break;
philpem@5 14486 default : {
philpem@5 14487 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14488 res(x,y,z,v) = (T)linear_atXYZV((float)warp(x,y,z,0),(float)warp(x,y,z,1),(float)warp(x,y,z,2),(float)warp(x,y,z,3),0);
philpem@5 14489 }
philpem@5 14490 } else switch (border_conditions) {
philpem@5 14491 case 2 : {
philpem@5 14492 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14493 res(x,y,z,v) = (*this)(cimg::mod((int)warp(x,y,z,0),(int)width),
philpem@5 14494 cimg::mod((int)warp(x,y,z,1),(int)height),
philpem@5 14495 cimg::mod((int)warp(x,y,z,2),(int)depth),
philpem@5 14496 cimg::mod((int)warp(x,y,z,3),(int)dim));
philpem@5 14497 } break;
philpem@5 14498 case 1 : {
philpem@5 14499 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14500 res(x,y,z,v) = _atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3));
philpem@5 14501 } break;
philpem@5 14502 default : {
philpem@5 14503 cimg_forXYZV(*this,x,y,z,v)
philpem@5 14504 res(x,y,z,v) = atXYZV((int)warp(x,y,z,0),(int)warp(x,y,z,1),(int)warp(x,y,z,2),(int)warp(x,y,z,3),0);
philpem@5 14505 }
philpem@5 14506 }
philpem@5 14507 }
philpem@5 14508 }
philpem@5 14509 return res;
philpem@5 14510 }
philpem@5 14511
philpem@5 14512 // Permute axes order (internal).
philpem@5 14513 template<typename t>
philpem@5 14514 CImg<t> _get_permute_axes(const char *permut, const t&) const {
philpem@5 14515 if (is_empty() || !permut) return CImg<t>(*this,false);
philpem@5 14516 CImg<t> res;
philpem@5 14517 const T* ptrs = data;
philpem@5 14518 if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this);
philpem@5 14519 if (!cimg::strncasecmp(permut,"xyvz",4)) {
philpem@5 14520 res.assign(width,height,dim,depth);
philpem@5 14521 cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = (t)*(ptrs++);
philpem@5 14522 }
philpem@5 14523 if (!cimg::strncasecmp(permut,"xzyv",4)) {
philpem@5 14524 res.assign(width,depth,height,dim);
philpem@5 14525 cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = (t)*(ptrs++);
philpem@5 14526 }
philpem@5 14527 if (!cimg::strncasecmp(permut,"xzvy",4)) {
philpem@5 14528 res.assign(width,depth,dim,height);
philpem@5 14529 cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = (t)*(ptrs++);
philpem@5 14530 }
philpem@5 14531 if (!cimg::strncasecmp(permut,"xvyz",4)) {
philpem@5 14532 res.assign(width,dim,height,depth);
philpem@5 14533 cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = (t)*(ptrs++);
philpem@5 14534 }
philpem@5 14535 if (!cimg::strncasecmp(permut,"xvzy",4)) {
philpem@5 14536 res.assign(width,dim,depth,height);
philpem@5 14537 cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = (t)*(ptrs++);
philpem@5 14538 }
philpem@5 14539 if (!cimg::strncasecmp(permut,"yxzv",4)) {
philpem@5 14540 res.assign(height,width,depth,dim);
philpem@5 14541 cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (t)*(ptrs++);
philpem@5 14542 }
philpem@5 14543 if (!cimg::strncasecmp(permut,"yxvz",4)) {
philpem@5 14544 res.assign(height,width,dim,depth);
philpem@5 14545 cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = (t)*(ptrs++);
philpem@5 14546 }
philpem@5 14547 if (!cimg::strncasecmp(permut,"yzxv",4)) {
philpem@5 14548 res.assign(height,depth,width,dim);
philpem@5 14549 cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = (t)*(ptrs++);
philpem@5 14550 }
philpem@5 14551 if (!cimg::strncasecmp(permut,"yzvx",4)) {
philpem@5 14552 res.assign(height,depth,dim,width);
philpem@5 14553 switch (width) {
philpem@5 14554 case 1 : {
philpem@5 14555 t *ptrR = res.ptr(0,0,0,0);
philpem@5 14556 for (unsigned long siz = height*depth*dim; siz; --siz) {
philpem@5 14557 *(ptrR++) = (t)*(ptrs++);
philpem@5 14558 }
philpem@5 14559 } break;
philpem@5 14560 case 2 : {
philpem@5 14561 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1);
philpem@5 14562 for (unsigned long siz = height*depth*dim; siz; --siz) {
philpem@5 14563 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++);
philpem@5 14564 }
philpem@5 14565 } break;
philpem@5 14566 case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB
philpem@5 14567 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2);
philpem@5 14568 for (unsigned long siz = height*depth*dim; siz; --siz) {
philpem@5 14569 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++);
philpem@5 14570 }
philpem@5 14571 } break;
philpem@5 14572 case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA
philpem@5 14573 t *ptrR = res.ptr(0,0,0,0), *ptrG = res.ptr(0,0,0,1), *ptrB = res.ptr(0,0,0,2), *ptrA = res.ptr(0,0,0,3);
philpem@5 14574 for (unsigned long siz = height*depth*dim; siz; --siz) {
philpem@5 14575 *(ptrR++) = (t)*(ptrs++); *(ptrG++) = (t)*(ptrs++); *(ptrB++) = (t)*(ptrs++); *(ptrA++) = (t)*(ptrs++);
philpem@5 14576 }
philpem@5 14577 } break;
philpem@5 14578 default : {
philpem@5 14579 cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptrs++);
philpem@5 14580 return res;
philpem@5 14581 }
philpem@5 14582 }
philpem@5 14583 }
philpem@5 14584 if (!cimg::strncasecmp(permut,"yvxz",4)) {
philpem@5 14585 res.assign(height,dim,width,depth);
philpem@5 14586 cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = (t)*(ptrs++);
philpem@5 14587 }
philpem@5 14588 if (!cimg::strncasecmp(permut,"yvzx",4)) {
philpem@5 14589 res.assign(height,dim,depth,width);
philpem@5 14590 cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = (t)*(ptrs++);
philpem@5 14591 }
philpem@5 14592 if (!cimg::strncasecmp(permut,"zxyv",4)) {
philpem@5 14593 res.assign(depth,width,height,dim);
philpem@5 14594 cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = (t)*(ptrs++);
philpem@5 14595 }
philpem@5 14596 if (!cimg::strncasecmp(permut,"zxvy",4)) {
philpem@5 14597 res.assign(depth,width,dim,height);
philpem@5 14598 cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = (t)*(ptrs++);
philpem@5 14599 }
philpem@5 14600 if (!cimg::strncasecmp(permut,"zyxv",4)) {
philpem@5 14601 res.assign(depth,height,width,dim);
philpem@5 14602 cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = (t)*(ptrs++);
philpem@5 14603 }
philpem@5 14604 if (!cimg::strncasecmp(permut,"zyvx",4)) {
philpem@5 14605 res.assign(depth,height,dim,width);
philpem@5 14606 cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = (t)*(ptrs++);
philpem@5 14607 }
philpem@5 14608 if (!cimg::strncasecmp(permut,"zvxy",4)) {
philpem@5 14609 res.assign(depth,dim,width,height);
philpem@5 14610 cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = (t)*(ptrs++);
philpem@5 14611 }
philpem@5 14612 if (!cimg::strncasecmp(permut,"zvyx",4)) {
philpem@5 14613 res.assign(depth,dim,height,width);
philpem@5 14614 cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = (t)*(ptrs++);
philpem@5 14615 }
philpem@5 14616 if (!cimg::strncasecmp(permut,"vxyz",4)) {
philpem@5 14617 res.assign(dim,width,height,depth);
philpem@5 14618 switch (dim) {
philpem@5 14619 case 1 : {
philpem@5 14620 const T *ptrR = ptr(0,0,0,0);
philpem@5 14621 t *ptrd = res.ptr();
philpem@5 14622 for (unsigned long siz = width*height*depth; siz; --siz) {
philpem@5 14623 *(ptrd++) = (t)*(ptrR++);
philpem@5 14624 }
philpem@5 14625 } break;
philpem@5 14626 case 2 : {
philpem@5 14627 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1);
philpem@5 14628 t *ptrd = res.ptr();
philpem@5 14629 for (unsigned long siz = width*height*depth; siz; --siz) {
philpem@5 14630 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++);
philpem@5 14631 }
philpem@5 14632 } break;
philpem@5 14633 case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB
philpem@5 14634 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2);
philpem@5 14635 t *ptrd = res.ptr();
philpem@5 14636 for (unsigned long siz = width*height*depth; siz; --siz) {
philpem@5 14637 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++);
philpem@5 14638 }
philpem@5 14639 } break;
philpem@5 14640 case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA
philpem@5 14641 const T *ptrR = ptr(0,0,0,0), *ptrG = ptr(0,0,0,1), *ptrB = ptr(0,0,0,2), *ptrA = ptr(0,0,0,3);
philpem@5 14642 t *ptrd = res.ptr();
philpem@5 14643 for (unsigned long siz = width*height*depth; siz; --siz) {
philpem@5 14644 *(ptrd++) = (t)*(ptrR++); *(ptrd++) = (t)*(ptrG++); *(ptrd++) = (t)*(ptrB++); *(ptrd++) = (t)*(ptrA++);
philpem@5 14645 }
philpem@5 14646 } break;
philpem@5 14647 default : {
philpem@5 14648 cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = (t)*(ptrs++);
philpem@5 14649 }
philpem@5 14650 }
philpem@5 14651 }
philpem@5 14652 if (!cimg::strncasecmp(permut,"vxzy",4)) {
philpem@5 14653 res.assign(dim,width,depth,height);
philpem@5 14654 cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = (t)*(ptrs++);
philpem@5 14655 }
philpem@5 14656 if (!cimg::strncasecmp(permut,"vyxz",4)) {
philpem@5 14657 res.assign(dim,height,width,depth);
philpem@5 14658 cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = (t)*(ptrs++);
philpem@5 14659 }
philpem@5 14660 if (!cimg::strncasecmp(permut,"vyzx",4)) {
philpem@5 14661 res.assign(dim,height,depth,width);
philpem@5 14662 cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = (t)*(ptrs++);
philpem@5 14663 }
philpem@5 14664 if (!cimg::strncasecmp(permut,"vzxy",4)) {
philpem@5 14665 res.assign(dim,depth,width,height);
philpem@5 14666 cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = (t)*(ptrs++);
philpem@5 14667 }
philpem@5 14668 if (!cimg::strncasecmp(permut,"vzyx",4)) {
philpem@5 14669 res.assign(dim,depth,height,width);
philpem@5 14670 cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = (t)*(ptrs++);
philpem@5 14671 }
philpem@5 14672 if (!res)
philpem@5 14673 throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",
philpem@5 14674 pixel_type(),permut);
philpem@5 14675 return res;
philpem@5 14676 }
philpem@5 14677
philpem@5 14678 //! Permute axes order.
philpem@5 14679 /**
philpem@5 14680 This function permutes image axes.
philpem@5 14681 \param permut = String describing the permutation (4 characters).
philpem@5 14682 **/
philpem@5 14683 CImg<T>& permute_axes(const char *order) {
philpem@5 14684 return get_permute_axes(order).transfer_to(*this);
philpem@5 14685 }
philpem@5 14686
philpem@5 14687 CImg<T> get_permute_axes(const char *order) const {
philpem@5 14688 const T foo = (T)0;
philpem@5 14689 return _get_permute_axes(order,foo);
philpem@5 14690 }
philpem@5 14691
philpem@5 14692 //! Invert endianness.
philpem@5 14693 CImg<T>& invert_endianness() {
philpem@5 14694 cimg::invert_endianness(data,size());
philpem@5 14695 return *this;
philpem@5 14696 }
philpem@5 14697
philpem@5 14698 CImg<T> get_invert_endianness() const {
philpem@5 14699 return (+*this).invert_endianness();
philpem@5 14700 }
philpem@5 14701
philpem@5 14702 //! Mirror an image along the specified axis.
philpem@5 14703 CImg<T>& mirror(const char axis) {
philpem@5 14704 if (is_empty()) return *this;
philpem@5 14705 T *pf, *pb, *buf = 0;
philpem@5 14706 switch (cimg::uncase(axis)) {
philpem@5 14707 case 'x' : {
philpem@5 14708 pf = data; pb = ptr(width-1);
philpem@5 14709 const unsigned int width2 = width/2;
philpem@5 14710 for (unsigned int yzv = 0; yzv<height*depth*dim; ++yzv) {
philpem@5 14711 for (unsigned int x = 0; x<width2; ++x) { const T val = *pf; *(pf++) = *pb; *(pb--) = val; }
philpem@5 14712 pf+=width - width2;
philpem@5 14713 pb+=width + width2;
philpem@5 14714 }
philpem@5 14715 } break;
philpem@5 14716 case 'y' : {
philpem@5 14717 buf = new T[width];
philpem@5 14718 pf = data; pb = ptr(0,height-1);
philpem@5 14719 const unsigned int height2 = height/2;
philpem@5 14720 for (unsigned int zv=0; zv<depth*dim; ++zv) {
philpem@5 14721 for (unsigned int y=0; y<height2; ++y) {
philpem@5 14722 cimg_std::memcpy(buf,pf,width*sizeof(T));
philpem@5 14723 cimg_std::memcpy(pf,pb,width*sizeof(T));
philpem@5 14724 cimg_std::memcpy(pb,buf,width*sizeof(T));
philpem@5 14725 pf+=width;
philpem@5 14726 pb-=width;
philpem@5 14727 }
philpem@5 14728 pf+=width*(height - height2);
philpem@5 14729 pb+=width*(height + height2);
philpem@5 14730 }
philpem@5 14731 } break;
philpem@5 14732 case 'z' : {
philpem@5 14733 buf = new T[width*height];
philpem@5 14734 pf = data; pb = ptr(0,0,depth-1);
philpem@5 14735 const unsigned int depth2 = depth/2;
philpem@5 14736 cimg_forV(*this,v) {
philpem@5 14737 for (unsigned int z=0; z<depth2; ++z) {
philpem@5 14738 cimg_std::memcpy(buf,pf,width*height*sizeof(T));
philpem@5 14739 cimg_std::memcpy(pf,pb,width*height*sizeof(T));
philpem@5 14740 cimg_std::memcpy(pb,buf,width*height*sizeof(T));
philpem@5 14741 pf+=width*height;
philpem@5 14742 pb-=width*height;
philpem@5 14743 }
philpem@5 14744 pf+=width*height*(depth - depth2);
philpem@5 14745 pb+=width*height*(depth + depth2);
philpem@5 14746 }
philpem@5 14747 } break;
philpem@5 14748 case 'v' : {
philpem@5 14749 buf = new T[width*height*depth];
philpem@5 14750 pf = data; pb = ptr(0,0,0,dim-1);
philpem@5 14751 const unsigned int dim2 = dim/2;
philpem@5 14752 for (unsigned int v=0; v<dim2; ++v) {
philpem@5 14753 cimg_std::memcpy(buf,pf,width*height*depth*sizeof(T));
philpem@5 14754 cimg_std::memcpy(pf,pb,width*height*depth*sizeof(T));
philpem@5 14755 cimg_std::memcpy(pb,buf,width*height*depth*sizeof(T));
philpem@5 14756 pf+=width*height*depth;
philpem@5 14757 pb-=width*height*depth;
philpem@5 14758 }
philpem@5 14759 } break;
philpem@5 14760 default :
philpem@5 14761 throw CImgArgumentException("CImg<%s>::mirror() : unknow axis '%c', must be 'x','y','z' or 'v'.",
philpem@5 14762 pixel_type(),axis);
philpem@5 14763 }
philpem@5 14764 if (buf) delete[] buf;
philpem@5 14765 return *this;
philpem@5 14766 }
philpem@5 14767
philpem@5 14768 CImg<T> get_mirror(const char axis) const {
philpem@5 14769 return (+*this).mirror(axis);
philpem@5 14770 }
philpem@5 14771
philpem@5 14772 //! Translate the image.
philpem@5 14773 /**
philpem@5 14774 \param deltax Amount of displacement along the X-axis.
philpem@5 14775 \param deltay Amount of displacement along the Y-axis.
philpem@5 14776 \param deltaz Amount of displacement along the Z-axis.
philpem@5 14777 \param deltav Amount of displacement along the V-axis.
philpem@5 14778 \param border_condition Border condition.
philpem@5 14779
philpem@5 14780 - \c border_condition can be :
philpem@5 14781 - 0 : Zero border condition (Dirichlet).
philpem@5 14782 - 1 : Nearest neighbors (Neumann).
philpem@5 14783 - 2 : Repeat Pattern (Fourier style).
philpem@5 14784 **/
philpem@5 14785 CImg<T>& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
philpem@5 14786 const int border_condition=0) {
philpem@5 14787 if (is_empty()) return *this;
philpem@5 14788 if (deltax) // Translate along X-axis
philpem@5 14789 switch (border_condition) {
philpem@5 14790 case 0 :
philpem@5 14791 if (cimg::abs(deltax)>=dimx()) return fill(0);
philpem@5 14792 if (deltax>0) cimg_forYZV(*this,y,z,k) {
philpem@5 14793 cimg_std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T));
philpem@5 14794 cimg_std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T));
philpem@5 14795 } else cimg_forYZV(*this,y,z,k) {
philpem@5 14796 cimg_std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T));
philpem@5 14797 cimg_std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T));
philpem@5 14798 }
philpem@5 14799 break;
philpem@5 14800 case 1 :
philpem@5 14801 if (deltax>0) {
philpem@5 14802 const int ndeltax = (deltax>=dimx())?width-1:deltax;
philpem@5 14803 if (!ndeltax) return *this;
philpem@5 14804 cimg_forYZV(*this,y,z,k) {
philpem@5 14805 cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
philpem@5 14806 T *ptrd = ptr(width-1,y,z,k);
philpem@5 14807 const T val = *ptrd;
philpem@5 14808 for (int l = 0; l<ndeltax-1; ++l) *(--ptrd) = val;
philpem@5 14809 }
philpem@5 14810 } else {
philpem@5 14811 const int ndeltax = (-deltax>=dimx())?width-1:-deltax;
philpem@5 14812 if (!ndeltax) return *this;
philpem@5 14813 cimg_forYZV(*this,y,z,k) {
philpem@5 14814 cimg_std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T));
philpem@5 14815 T *ptrd = ptr(0,y,z,k);
philpem@5 14816 const T val = *ptrd;
philpem@5 14817 for (int l = 0; l<ndeltax-1; ++l) *(++ptrd) = val;
philpem@5 14818 }
philpem@5 14819 }
philpem@5 14820 break;
philpem@5 14821 case 2 : {
philpem@5 14822 const int ml = cimg::mod(deltax,dimx()), ndeltax = (ml<=dimx()/2)?ml:(ml-dimx());
philpem@5 14823 if (!ndeltax) return *this;
philpem@5 14824 T* buf = new T[cimg::abs(ndeltax)];
philpem@5 14825 if (ndeltax>0) cimg_forYZV(*this,y,z,k) {
philpem@5 14826 cimg_std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T));
philpem@5 14827 cimg_std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T));
philpem@5 14828 cimg_std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T));
philpem@5 14829 } else cimg_forYZV(*this,y,z,k) {
philpem@5 14830 cimg_std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T));
philpem@5 14831 cimg_std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T));
philpem@5 14832 cimg_std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T));
philpem@5 14833 }
philpem@5 14834 delete[] buf;
philpem@5 14835 } break;
philpem@5 14836 }
philpem@5 14837
philpem@5 14838 if (deltay) // Translate along Y-axis
philpem@5 14839 switch (border_condition) {
philpem@5 14840 case 0 :
philpem@5 14841 if (cimg::abs(deltay)>=dimy()) return fill(0);
philpem@5 14842 if (deltay>0) cimg_forZV(*this,z,k) {
philpem@5 14843 cimg_std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T));
philpem@5 14844 cimg_std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T));
philpem@5 14845 } else cimg_forZV(*this,z,k) {
philpem@5 14846 cimg_std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T));
philpem@5 14847 cimg_std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T));
philpem@5 14848 }
philpem@5 14849 break;
philpem@5 14850 case 1 :
philpem@5 14851 if (deltay>0) {
philpem@5 14852 const int ndeltay = (deltay>=dimy())?height-1:deltay;
philpem@5 14853 if (!ndeltay) return *this;
philpem@5 14854 cimg_forZV(*this,z,k) {
philpem@5 14855 cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
philpem@5 14856 T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k);
philpem@5 14857 for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
philpem@5 14858 }
philpem@5 14859 } else {
philpem@5 14860 const int ndeltay = (-deltay>=dimy())?height-1:-deltay;
philpem@5 14861 if (!ndeltay) return *this;
philpem@5 14862 cimg_forZV(*this,z,k) {
philpem@5 14863 cimg_std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T));
philpem@5 14864 T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k);
philpem@5 14865 for (int l = 0; l<ndeltay-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; }
philpem@5 14866 }
philpem@5 14867 }
philpem@5 14868 break;
philpem@5 14869 case 2 : {
philpem@5 14870 const int ml = cimg::mod(deltay,dimy()), ndeltay = (ml<=dimy()/2)?ml:(ml-dimy());
philpem@5 14871 if (!ndeltay) return *this;
philpem@5 14872 T* buf = new T[width*cimg::abs(ndeltay)];
philpem@5 14873 if (ndeltay>0) cimg_forZV(*this,z,k) {
philpem@5 14874 cimg_std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T));
philpem@5 14875 cimg_std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T));
philpem@5 14876 cimg_std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T));
philpem@5 14877 } else cimg_forZV(*this,z,k) {
philpem@5 14878 cimg_std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T));
philpem@5 14879 cimg_std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T));
philpem@5 14880 cimg_std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T));
philpem@5 14881 }
philpem@5 14882 delete[] buf;
philpem@5 14883 } break;
philpem@5 14884 }
philpem@5 14885
philpem@5 14886 if (deltaz) // Translate along Z-axis
philpem@5 14887 switch (border_condition) {
philpem@5 14888 case 0 :
philpem@5 14889 if (cimg::abs(deltaz)>=dimz()) return fill(0);
philpem@5 14890 if (deltaz>0) cimg_forV(*this,k) {
philpem@5 14891 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T));
philpem@5 14892 cimg_std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T));
philpem@5 14893 } else cimg_forV(*this,k) {
philpem@5 14894 cimg_std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T));
philpem@5 14895 cimg_std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T));
philpem@5 14896 }
philpem@5 14897 break;
philpem@5 14898 case 1 :
philpem@5 14899 if (deltaz>0) {
philpem@5 14900 const int ndeltaz = (deltaz>=dimz())?depth-1:deltaz;
philpem@5 14901 if (!ndeltaz) return *this;
philpem@5 14902 cimg_forV(*this,k) {
philpem@5 14903 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
philpem@5 14904 T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k);
philpem@5 14905 for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
philpem@5 14906 }
philpem@5 14907 } else {
philpem@5 14908 const int ndeltaz = (-deltaz>=dimz())?depth-1:-deltaz;
philpem@5 14909 if (!ndeltaz) return *this;
philpem@5 14910 cimg_forV(*this,k) {
philpem@5 14911 cimg_std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T));
philpem@5 14912 T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k);
philpem@5 14913 for (int l = 0; l<ndeltaz-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; }
philpem@5 14914 }
philpem@5 14915 }
philpem@5 14916 break;
philpem@5 14917 case 2 : {
philpem@5 14918 const int ml = cimg::mod(deltaz,dimz()), ndeltaz = (ml<=dimz()/2)?ml:(ml-dimz());
philpem@5 14919 if (!ndeltaz) return *this;
philpem@5 14920 T* buf = new T[width*height*cimg::abs(ndeltaz)];
philpem@5 14921 if (ndeltaz>0) cimg_forV(*this,k) {
philpem@5 14922 cimg_std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T));
philpem@5 14923 cimg_std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T));
philpem@5 14924 cimg_std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T));
philpem@5 14925 } else cimg_forV(*this,k) {
philpem@5 14926 cimg_std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T));
philpem@5 14927 cimg_std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T));
philpem@5 14928 cimg_std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T));
philpem@5 14929 }
philpem@5 14930 delete[] buf;
philpem@5 14931 } break;
philpem@5 14932 }
philpem@5 14933
philpem@5 14934 if (deltav) // Translate along V-axis
philpem@5 14935 switch (border_condition) {
philpem@5 14936 case 0 :
philpem@5 14937 if (cimg::abs(deltav)>=dimv()) return fill(0);
philpem@5 14938 if (deltav>0) {
philpem@5 14939 cimg_std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T));
philpem@5 14940 cimg_std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T));
philpem@5 14941 } else cimg_forV(*this,k) {
philpem@5 14942 cimg_std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T));
philpem@5 14943 cimg_std::memset(data,0,-deltav*width*height*depth*sizeof(T));
philpem@5 14944 }
philpem@5 14945 break;
philpem@5 14946 case 1 :
philpem@5 14947 if (deltav>0) {
philpem@5 14948 const int ndeltav = (deltav>=dimv())?dim-1:deltav;
philpem@5 14949 if (!ndeltav) return *this;
philpem@5 14950 cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
philpem@5 14951 T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1);
philpem@5 14952 for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
philpem@5 14953 } else {
philpem@5 14954 const int ndeltav = (-deltav>=dimv())?dim-1:-deltav;
philpem@5 14955 if (!ndeltav) return *this;
philpem@5 14956 cimg_std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T));
philpem@5 14957 T *ptrd = ptr(0,0,0,1);
philpem@5 14958 for (int l = 0; l<ndeltav-1; ++l) { cimg_std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; }
philpem@5 14959 }
philpem@5 14960 break;
philpem@5 14961 case 2 : {
philpem@5 14962 const int ml = cimg::mod(deltav,dimv()), ndeltav = (ml<=dimv()/2)?ml:(ml-dimv());
philpem@5 14963 if (!ndeltav) return *this;
philpem@5 14964 T* buf = new T[width*height*depth*cimg::abs(ndeltav)];
philpem@5 14965 if (ndeltav>0) {
philpem@5 14966 cimg_std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T));
philpem@5 14967 cimg_std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T));
philpem@5 14968 cimg_std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T));
philpem@5 14969 } else {
philpem@5 14970 cimg_std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T));
philpem@5 14971 cimg_std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T));
philpem@5 14972 cimg_std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T));
philpem@5 14973 }
philpem@5 14974 delete[] buf;
philpem@5 14975 } break;
philpem@5 14976 }
philpem@5 14977 return *this;
philpem@5 14978 }
philpem@5 14979
philpem@5 14980 CImg<T> get_translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0,
philpem@5 14981 const int border_condition=0) const {
philpem@5 14982 return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition);
philpem@5 14983 }
philpem@5 14984
philpem@5 14985 //! Get a square region of the image.
philpem@5 14986 /**
philpem@5 14987 \param x0 = X-coordinate of the upper-left crop rectangle corner.
philpem@5 14988 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
philpem@5 14989 \param z0 = Z-coordinate of the upper-left crop rectangle corner.
philpem@5 14990 \param v0 = V-coordinate of the upper-left crop rectangle corner.
philpem@5 14991 \param x1 = X-coordinate of the lower-right crop rectangle corner.
philpem@5 14992 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
philpem@5 14993 \param z1 = Z-coordinate of the lower-right crop rectangle corner.
philpem@5 14994 \param v1 = V-coordinate of the lower-right crop rectangle corner.
philpem@5 14995 \param border_condition = Dirichlet (false) or Neumann border conditions.
philpem@5 14996 **/
philpem@5 14997 CImg<T>& crop(const int x0, const int y0, const int z0, const int v0,
philpem@5 14998 const int x1, const int y1, const int z1, const int v1,
philpem@5 14999 const bool border_condition=false) {
philpem@5 15000 return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).transfer_to(*this);
philpem@5 15001 }
philpem@5 15002
philpem@5 15003 CImg<T> get_crop(const int x0, const int y0, const int z0, const int v0,
philpem@5 15004 const int x1, const int y1, const int z1, const int v1,
philpem@5 15005 const bool border_condition=false) const {
philpem@5 15006 if (is_empty()) return *this;
philpem@5 15007 const int
philpem@5 15008 nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
philpem@5 15009 ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
philpem@5 15010 nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
philpem@5 15011 nv0 = v0<v1?v0:v1, nv1 = v0^v1^nv0;
philpem@5 15012 CImg<T> dest(1U+nx1-nx0,1U+ny1-ny0,1U+nz1-nz0,1U+nv1-nv0);
philpem@5 15013 if (nx0<0 || nx1>=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) {
philpem@5 15014 if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = _atXYZV(nx0+x,ny0+y,nz0+z,nv0+v);
philpem@5 15015 else dest.fill(0).draw_image(-nx0,-ny0,-nz0,-nv0,*this);
philpem@5 15016 } else dest.draw_image(-nx0,-ny0,-nz0,-nv0,*this);
philpem@5 15017 return dest;
philpem@5 15018 }
philpem@5 15019
philpem@5 15020 //! Get a rectangular part of the instance image.
philpem@5 15021 /**
philpem@5 15022 \param x0 = X-coordinate of the upper-left crop rectangle corner.
philpem@5 15023 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
philpem@5 15024 \param z0 = Z-coordinate of the upper-left crop rectangle corner.
philpem@5 15025 \param x1 = X-coordinate of the lower-right crop rectangle corner.
philpem@5 15026 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
philpem@5 15027 \param z1 = Z-coordinate of the lower-right crop rectangle corner.
philpem@5 15028 \param border_condition = determine the type of border condition if
philpem@5 15029 some of the desired region is outside the image.
philpem@5 15030 **/
philpem@5 15031 CImg<T>& crop(const int x0, const int y0, const int z0,
philpem@5 15032 const int x1, const int y1, const int z1,
philpem@5 15033 const bool border_condition=false) {
philpem@5 15034 return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
philpem@5 15035 }
philpem@5 15036
philpem@5 15037 CImg<T> get_crop(const int x0, const int y0, const int z0,
philpem@5 15038 const int x1, const int y1, const int z1,
philpem@5 15039 const bool border_condition=false) const {
philpem@5 15040 return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition);
philpem@5 15041 }
philpem@5 15042
philpem@5 15043 //! Get a rectangular part of the instance image.
philpem@5 15044 /**
philpem@5 15045 \param x0 = X-coordinate of the upper-left crop rectangle corner.
philpem@5 15046 \param y0 = Y-coordinate of the upper-left crop rectangle corner.
philpem@5 15047 \param x1 = X-coordinate of the lower-right crop rectangle corner.
philpem@5 15048 \param y1 = Y-coordinate of the lower-right crop rectangle corner.
philpem@5 15049 \param border_condition = determine the type of border condition if
philpem@5 15050 some of the desired region is outside the image.
philpem@5 15051 **/
philpem@5 15052 CImg<T>& crop(const int x0, const int y0,
philpem@5 15053 const int x1, const int y1,
philpem@5 15054 const bool border_condition=false) {
philpem@5 15055 return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
philpem@5 15056 }
philpem@5 15057
philpem@5 15058 CImg<T> get_crop(const int x0, const int y0,
philpem@5 15059 const int x1, const int y1,
philpem@5 15060 const bool border_condition=false) const {
philpem@5 15061 return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition);
philpem@5 15062 }
philpem@5 15063
philpem@5 15064 //! Get a rectangular part of the instance image.
philpem@5 15065 /**
philpem@5 15066 \param x0 = X-coordinate of the upper-left crop rectangle corner.
philpem@5 15067 \param x1 = X-coordinate of the lower-right crop rectangle corner.
philpem@5 15068 \param border_condition = determine the type of border condition if
philpem@5 15069 some of the desired region is outside the image.
philpem@5 15070 **/
philpem@5 15071 CImg<T>& crop(const int x0, const int x1, const bool border_condition=false) {
philpem@5 15072 return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
philpem@5 15073 }
philpem@5 15074
philpem@5 15075 CImg<T> get_crop(const int x0, const int x1, const bool border_condition=false) const {
philpem@5 15076 return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition);
philpem@5 15077 }
philpem@5 15078
philpem@5 15079 //! Autocrop an image, regarding of the specified backround value.
philpem@5 15080 CImg<T>& autocrop(const T value, const char *const axes="vzyx") {
philpem@5 15081 if (is_empty()) return *this;
philpem@5 15082 const int lmax = cimg::strlen(axes);
philpem@5 15083 for (int l = 0; l<lmax; ++l) autocrop(value,axes[l]);
philpem@5 15084 return *this;
philpem@5 15085 }
philpem@5 15086
philpem@5 15087 CImg<T> get_autocrop(const T value, const char *const axes="vzyx") const {
philpem@5 15088 return (+*this).autocrop(value,axes);
philpem@5 15089 }
philpem@5 15090
philpem@5 15091 //! Autocrop an image, regarding of the specified backround color.
philpem@5 15092 CImg<T>& autocrop(const T *const color, const char *const axes="zyx") {
philpem@5 15093 if (is_empty()) return *this;
philpem@5 15094 const int lmax = cimg::strlen(axes);
philpem@5 15095 for (int l = 0; l<lmax; ++l) autocrop(color,axes[l]);
philpem@5 15096 return *this;
philpem@5 15097 }
philpem@5 15098
philpem@5 15099 CImg<T> get_autocrop(const T *const color, const char *const axes="zyx") const {
philpem@5 15100 return (+*this).autocrop(color,axes);
philpem@5 15101 }
philpem@5 15102
philpem@5 15103 //! Autocrop an image, regarding of the specified backround color.
philpem@5 15104 template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char *const axes="zyx") {
philpem@5 15105 return get_autocrop(color,axes).transfer_to(*this);
philpem@5 15106 }
philpem@5 15107
philpem@5 15108 template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char *const axes="zyx") const {
philpem@5 15109 return get_autocrop(color.data,axes);
philpem@5 15110 }
philpem@5 15111
philpem@5 15112 //! Autocrop an image along specified axis, regarding of the specified backround value.
philpem@5 15113 CImg<T>& autocrop(const T value, const char axis) {
philpem@5 15114 return get_autocrop(value,axis).transfer_to(*this);
philpem@5 15115 }
philpem@5 15116
philpem@5 15117 CImg<T> get_autocrop(const T value, const char axis) const {
philpem@5 15118 if (is_empty()) return *this;
philpem@5 15119 CImg<T> res;
philpem@5 15120 const CImg<intT> coords = _get_autocrop(value,axis);
philpem@5 15121 switch (cimg::uncase(axis)) {
philpem@5 15122 case 'x' : {
philpem@5 15123 const int x0 = coords[0], x1 = coords[1];
philpem@5 15124 if (x0>=0 && x1>=0) res = get_crop(x0,x1);
philpem@5 15125 } break;
philpem@5 15126 case 'y' : {
philpem@5 15127 const int y0 = coords[0], y1 = coords[1];
philpem@5 15128 if (y0>=0 && y1>=0) res = get_crop(0,y0,width-1,y1);
philpem@5 15129 } break;
philpem@5 15130 case 'z' : {
philpem@5 15131 const int z0 = coords[0], z1 = coords[1];
philpem@5 15132 if (z0>=0 && z1>=0) res = get_crop(0,0,z0,width-1,height-1,z1);
philpem@5 15133 } break;
philpem@5 15134 case 'v' : {
philpem@5 15135 const int v0 = coords[0], v1 = coords[1];
philpem@5 15136 if (v0>=0 && v1>=0) res = get_crop(0,0,0,v0,width-1,height-1,depth-1,v1);
philpem@5 15137 } break;
philpem@5 15138 }
philpem@5 15139 return res;
philpem@5 15140 }
philpem@5 15141
philpem@5 15142 //! Autocrop an image along specified axis, regarding of the specified backround color.
philpem@5 15143 CImg<T>& autocrop(const T *const color, const char axis) {
philpem@5 15144 return get_autocrop(color,axis).transfer_to(*this);
philpem@5 15145 }
philpem@5 15146
philpem@5 15147 CImg<T> get_autocrop(const T *const color, const char axis) const {
philpem@5 15148 if (is_empty()) return *this;
philpem@5 15149 CImg<T> res;
philpem@5 15150 switch (cimg::uncase(axis)) {
philpem@5 15151 case 'x' : {
philpem@5 15152 int x0 = width, x1 = -1;
philpem@5 15153 cimg_forV(*this,k) {
philpem@5 15154 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
philpem@5 15155 const int nx0 = coords[0], nx1 = coords[1];
philpem@5 15156 if (nx0>=0 && nx1>=0) { x0 = cimg::min(x0,nx0); x1 = cimg::max(x1,nx1); }
philpem@5 15157 }
philpem@5 15158 if (x0<=x1) res = get_crop(x0,x1);
philpem@5 15159 } break;
philpem@5 15160 case 'y' : {
philpem@5 15161 int y0 = height, y1 = -1;
philpem@5 15162 cimg_forV(*this,k) {
philpem@5 15163 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
philpem@5 15164 const int ny0 = coords[0], ny1 = coords[1];
philpem@5 15165 if (ny0>=0 && ny1>=0) { y0 = cimg::min(y0,ny0); y1 = cimg::max(y1,ny1); }
philpem@5 15166 }
philpem@5 15167 if (y0<=y1) res = get_crop(0,y0,width-1,y1);
philpem@5 15168 } break;
philpem@5 15169 case 'z' : {
philpem@5 15170 int z0 = depth, z1 = -1;
philpem@5 15171 cimg_forV(*this,k) {
philpem@5 15172 const CImg<intT> coords = get_shared_channel(k)._get_autocrop(color[k],axis);
philpem@5 15173 const int nz0 = coords[0], nz1 = coords[1];
philpem@5 15174 if (nz0>=0 && nz1>=0) { z0 = cimg::min(z0,nz0); z1 = cimg::max(z1,nz1); }
philpem@5 15175 }
philpem@5 15176 if (z0<=z1) res = get_crop(0,0,z0,width-1,height-1,z1);
philpem@5 15177 } break;
philpem@5 15178 default :
philpem@5 15179 throw CImgArgumentException("CImg<%s>::autocrop() : Invalid axis '%c', must be 'x','y' or 'z'.",
philpem@5 15180 pixel_type(),axis);
philpem@5 15181 }
philpem@5 15182 return res;
philpem@5 15183 }
philpem@5 15184
philpem@5 15185 //! Autocrop an image along specified axis, regarding of the specified backround color.
philpem@5 15186 template<typename t> CImg<T>& autocrop(const CImg<t>& color, const char axis) {
philpem@5 15187 return get_autocrop(color,axis).transfer_to(*this);
philpem@5 15188 }
philpem@5 15189
philpem@5 15190 template<typename t> CImg<T> get_autocrop(const CImg<t>& color, const char axis) const {
philpem@5 15191 return get_autocrop(color.data,axis);
philpem@5 15192 }
philpem@5 15193
philpem@5 15194 CImg<intT> _get_autocrop(const T value, const char axis) const {
philpem@5 15195 CImg<intT> res;
philpem@5 15196 int x0 = -1, y0 = -1, z0 = -1, v0 = -1, x1 = -1, y1 = -1, z1 = -1, v1 = -1;
philpem@5 15197 switch (cimg::uncase(axis)) {
philpem@5 15198 case 'x' : {
philpem@5 15199 cimg_forX(*this,x) cimg_forYZV(*this,y,z,v)
philpem@5 15200 if ((*this)(x,y,z,v)!=value) { x0 = x; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
philpem@5 15201 if (x0>=0) {
philpem@5 15202 for (int x = dimx()-1; x>=0; --x) cimg_forYZV(*this,y,z,v)
philpem@5 15203 if ((*this)(x,y,z,v)!=value) { x1 = x; x = 0; y = dimy(); z = dimz(); v = dimv(); }
philpem@5 15204 }
philpem@5 15205 res = CImg<intT>::vector(x0,x1);
philpem@5 15206 } break;
philpem@5 15207 case 'y' : {
philpem@5 15208 cimg_forY(*this,y) cimg_forXZV(*this,x,z,v)
philpem@5 15209 if ((*this)(x,y,z,v)!=value) { y0 = y; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
philpem@5 15210 if (y0>=0) {
philpem@5 15211 for (int y = dimy()-1; y>=0; --y) cimg_forXZV(*this,x,z,v)
philpem@5 15212 if ((*this)(x,y,z,v)!=value) { y1 = y; x = dimx(); y = 0; z = dimz(); v = dimv(); }
philpem@5 15213 }
philpem@5 15214 res = CImg<intT>::vector(y0,y1);
philpem@5 15215 } break;
philpem@5 15216 case 'z' : {
philpem@5 15217 cimg_forZ(*this,z) cimg_forXYV(*this,x,y,v)
philpem@5 15218 if ((*this)(x,y,z,v)!=value) { z0 = z; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
philpem@5 15219 if (z0>=0) {
philpem@5 15220 for (int z = dimz()-1; z>=0; --z) cimg_forXYV(*this,x,y,v)
philpem@5 15221 if ((*this)(x,y,z,v)!=value) { z1 = z; x = dimx(); y = dimy(); z = 0; v = dimv(); }
philpem@5 15222 }
philpem@5 15223 res = CImg<intT>::vector(z0,z1);
philpem@5 15224 } break;
philpem@5 15225 case 'v' : {
philpem@5 15226 cimg_forV(*this,v) cimg_forXYZ(*this,x,y,z)
philpem@5 15227 if ((*this)(x,y,z,v)!=value) { v0 = v; x = dimx(); y = dimy(); z = dimz(); v = dimv(); }
philpem@5 15228 if (v0>=0) {
philpem@5 15229 for (int v = dimv()-1; v>=0; --v) cimg_forXYZ(*this,x,y,z)
philpem@5 15230 if ((*this)(x,y,z,v)!=value) { v1 = v; x = dimx(); y = dimy(); z = dimz(); v = 0; }
philpem@5 15231 }
philpem@5 15232 res = CImg<intT>::vector(v0,v1);
philpem@5 15233 } break;
philpem@5 15234 default :
philpem@5 15235 throw CImgArgumentException("CImg<%s>::autocrop() : unknow axis '%c', must be 'x','y','z' or 'v'",
philpem@5 15236 pixel_type(),axis);
philpem@5 15237 }
philpem@5 15238 return res;
philpem@5 15239 }
philpem@5 15240
philpem@5 15241 //! Get a set of columns.
philpem@5 15242 CImg<T>& columns(const unsigned int x0, const unsigned int x1) {
philpem@5 15243 return get_columns(x0,x1).transfer_to(*this);
philpem@5 15244 }
philpem@5 15245
philpem@5 15246 CImg<T> get_columns(const unsigned int x0, const unsigned int x1) const {
philpem@5 15247 return get_crop((int)x0,0,0,0,(int)x1,dimy()-1,dimz()-1,dimv()-1);
philpem@5 15248 }
philpem@5 15249
philpem@5 15250 //! Get one column.
philpem@5 15251 CImg<T>& column(const unsigned int x0) {
philpem@5 15252 return columns(x0,x0);
philpem@5 15253 }
philpem@5 15254
philpem@5 15255 CImg<T> get_column(const unsigned int x0) const {
philpem@5 15256 return get_columns(x0,x0);
philpem@5 15257 }
philpem@5 15258
philpem@5 15259 //! Get a set of lines.
philpem@5 15260 CImg<T>& lines(const unsigned int y0, const unsigned int y1) {
philpem@5 15261 return get_lines(y0,y1).transfer_to(*this);
philpem@5 15262 }
philpem@5 15263
philpem@5 15264 CImg<T> get_lines(const unsigned int y0, const unsigned int y1) const {
philpem@5 15265 return get_crop(0,(int)y0,0,0,dimx()-1,(int)y1,dimz()-1,dimv()-1);
philpem@5 15266 }
philpem@5 15267
philpem@5 15268 //! Get a line.
philpem@5 15269 CImg<T>& line(const unsigned int y0) {
philpem@5 15270 return lines(y0,y0);
philpem@5 15271 }
philpem@5 15272
philpem@5 15273 CImg<T> get_line(const unsigned int y0) const {
philpem@5 15274 return get_lines(y0,y0);
philpem@5 15275 }
philpem@5 15276
philpem@5 15277 //! Get a set of slices.
philpem@5 15278 CImg<T>& slices(const unsigned int z0, const unsigned int z1) {
philpem@5 15279 return get_slices(z0,z1).transfer_to(*this);
philpem@5 15280 }
philpem@5 15281
philpem@5 15282 CImg<T> get_slices(const unsigned int z0, const unsigned int z1) const {
philpem@5 15283 return get_crop(0,0,(int)z0,0,dimx()-1,dimy()-1,(int)z1,dimv()-1);
philpem@5 15284 }
philpem@5 15285
philpem@5 15286 //! Get a slice.
philpem@5 15287 CImg<T>& slice(const unsigned int z0) {
philpem@5 15288 return slices(z0,z0);
philpem@5 15289 }
philpem@5 15290
philpem@5 15291 CImg<T> get_slice(const unsigned int z0) const {
philpem@5 15292 return get_slices(z0,z0);
philpem@5 15293 }
philpem@5 15294
philpem@5 15295 //! Get a set of channels.
philpem@5 15296 CImg<T>& channels(const unsigned int v0, const unsigned int v1) {
philpem@5 15297 return get_channels(v0,v1).transfer_to(*this);
philpem@5 15298 }
philpem@5 15299
philpem@5 15300 CImg<T> get_channels(const unsigned int v0, const unsigned int v1) const {
philpem@5 15301 return get_crop(0,0,0,(int)v0,dimx()-1,dimy()-1,dimz()-1,(int)v1);
philpem@5 15302 }
philpem@5 15303
philpem@5 15304 //! Get a channel.
philpem@5 15305 CImg<T>& channel(const unsigned int v0) {
philpem@5 15306 return channels(v0,v0);
philpem@5 15307 }
philpem@5 15308
philpem@5 15309 CImg<T> get_channel(const unsigned int v0) const {
philpem@5 15310 return get_channels(v0,v0);
philpem@5 15311 }
philpem@5 15312
philpem@5 15313 //! Get a shared-memory image referencing a set of points of the instance image.
philpem@5 15314 CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
philpem@5 15315 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) {
philpem@5 15316 const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
philpem@5 15317 if (beg>end || beg>=size() || end>=size())
philpem@5 15318 throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
philpem@5 15319 "a (%u,%u,%u,%u) image.",
philpem@5 15320 pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
philpem@5 15321 return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
philpem@5 15322 }
philpem@5 15323
philpem@5 15324 const CImg<T> get_shared_points(const unsigned int x0, const unsigned int x1,
philpem@5 15325 const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const {
philpem@5 15326 const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0);
philpem@5 15327 if (beg>end || beg>=size() || end>=size())
philpem@5 15328 throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from "
philpem@5 15329 "a (%u,%u,%u,%u) image.",
philpem@5 15330 pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim);
philpem@5 15331 return CImg<T>(data+beg,x1-x0+1,1,1,1,true);
philpem@5 15332 }
philpem@5 15333
philpem@5 15334 //! Return a shared-memory image referencing a set of lines of the instance image.
philpem@5 15335 CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
philpem@5 15336 const unsigned int z0=0, const unsigned int v0=0) {
philpem@5 15337 const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
philpem@5 15338 if (beg>end || beg>=size() || end>=size())
philpem@5 15339 throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
philpem@5 15340 "a (%u,%u,%u,%u) image.",
philpem@5 15341 pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
philpem@5 15342 return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
philpem@5 15343 }
philpem@5 15344
philpem@5 15345 const CImg<T> get_shared_lines(const unsigned int y0, const unsigned int y1,
philpem@5 15346 const unsigned int z0=0, const unsigned int v0=0) const {
philpem@5 15347 const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0);
philpem@5 15348 if (beg>end || beg>=size() || end>=size())
philpem@5 15349 throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from "
philpem@5 15350 "a (%u,%u,%u,%u) image.",
philpem@5 15351 pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim);
philpem@5 15352 return CImg<T>(data+beg,width,y1-y0+1,1,1,true);
philpem@5 15353 }
philpem@5 15354
philpem@5 15355 //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image.
philpem@5 15356 CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) {
philpem@5 15357 return get_shared_lines(y0,y0,z0,v0);
philpem@5 15358 }
philpem@5 15359
philpem@5 15360 const CImg<T> get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) const {
philpem@5 15361 return get_shared_lines(y0,y0,z0,v0);
philpem@5 15362 }
philpem@5 15363
philpem@5 15364 //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image.
philpem@5 15365 CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) {
philpem@5 15366 const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
philpem@5 15367 if (beg>end || beg>=size() || end>=size())
philpem@5 15368 throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
philpem@5 15369 "a (%u,%u,%u,%u) image.",
philpem@5 15370 pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
philpem@5 15371 return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
philpem@5 15372 }
philpem@5 15373
philpem@5 15374 const CImg<T> get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const {
philpem@5 15375 const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0);
philpem@5 15376 if (beg>end || beg>=size() || end>=size())
philpem@5 15377 throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from "
philpem@5 15378 "a (%u,%u,%u,%u) image.",
philpem@5 15379 pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim);
philpem@5 15380 return CImg<T>(data+beg,width,height,z1-z0+1,1,true);
philpem@5 15381 }
philpem@5 15382
philpem@5 15383 //! Return a shared-memory image referencing one plane (z0,v0) of the instance image.
philpem@5 15384 CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) {
philpem@5 15385 return get_shared_planes(z0,z0,v0);
philpem@5 15386 }
philpem@5 15387
philpem@5 15388 const CImg<T> get_shared_plane(const unsigned int z0, const unsigned int v0=0) const {
philpem@5 15389 return get_shared_planes(z0,z0,v0);
philpem@5 15390 }
philpem@5 15391
philpem@5 15392 //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image.
philpem@5 15393 CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) {
philpem@5 15394 const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
philpem@5 15395 if (beg>end || beg>=size() || end>=size())
philpem@5 15396 throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
philpem@5 15397 "a (%u,%u,%u,%u) image.",
philpem@5 15398 pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
philpem@5 15399 return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
philpem@5 15400 }
philpem@5 15401
philpem@5 15402 const CImg<T> get_shared_channels(const unsigned int v0, const unsigned int v1) const {
philpem@5 15403 const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1);
philpem@5 15404 if (beg>end || beg>=size() || end>=size())
philpem@5 15405 throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from "
philpem@5 15406 "a (%u,%u,%u,%u) image.",
philpem@5 15407 pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim);
philpem@5 15408 return CImg<T>(data+beg,width,height,depth,v1-v0+1,true);
philpem@5 15409 }
philpem@5 15410
philpem@5 15411 //! Return a shared-memory image referencing one channel v0 of the instance image.
philpem@5 15412 CImg<T> get_shared_channel(const unsigned int v0) {
philpem@5 15413 return get_shared_channels(v0,v0);
philpem@5 15414 }
philpem@5 15415
philpem@5 15416 const CImg<T> get_shared_channel(const unsigned int v0) const {
philpem@5 15417 return get_shared_channels(v0,v0);
philpem@5 15418 }
philpem@5 15419
philpem@5 15420 //! Return a shared version of the instance image.
philpem@5 15421 CImg<T> get_shared() {
philpem@5 15422 return CImg<T>(data,width,height,depth,dim,true);
philpem@5 15423 }
philpem@5 15424
philpem@5 15425 const CImg<T> get_shared() const {
philpem@5 15426 return CImg<T>(data,width,height,depth,dim,true);
philpem@5 15427 }
philpem@5 15428
philpem@5 15429 //! Return a 2D representation of a 3D image, with three slices.
philpem@5 15430 CImg<T>& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
philpem@5 15431 const int dx=-100, const int dy=-100, const int dz=-100) {
philpem@5 15432 return get_projections2d(x0,y0,z0,dx,dy,dz).transfer_to(*this);
philpem@5 15433 }
philpem@5 15434
philpem@5 15435 CImg<T> get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0,
philpem@5 15436 const int dx=-100, const int dy=-100, const int dz=-100) const {
philpem@5 15437 if (is_empty()) return *this;
philpem@5 15438 const unsigned int
philpem@5 15439 nx0 = (x0>=width)?width-1:x0,
philpem@5 15440 ny0 = (y0>=height)?height-1:y0,
philpem@5 15441 nz0 = (z0>=depth)?depth-1:z0;
philpem@5 15442 CImg<T>
philpem@5 15443 imgxy(width,height,1,dim),
philpem@5 15444 imgzy(depth,height,1,dim),
philpem@5 15445 imgxz(width,depth,1,dim);
philpem@5 15446 { cimg_forXYV(*this,x,y,k) imgxy(x,y,k) = (*this)(x,y,nz0,k); }
philpem@5 15447 { cimg_forYZV(*this,y,z,k) imgzy(z,y,k) = (*this)(nx0,y,z,k); }
philpem@5 15448 { cimg_forXZV(*this,x,z,k) imgxz(x,z,k) = (*this)(x,ny0,z,k); }
philpem@5 15449 imgxy.resize(dx,dy,1,dim,1);
philpem@5 15450 imgzy.resize(dz,dy,1,dim,1);
philpem@5 15451 imgxz.resize(dx,dz,1,dim,1);
philpem@5 15452 return CImg<T>(imgxy.width+imgzy.width,imgxy.height+imgxz.height,1,dim,0).
philpem@5 15453 draw_image(imgxy).draw_image(imgxy.width,imgzy).draw_image(0,imgxy.height,imgxz);
philpem@5 15454 }
philpem@5 15455
philpem@5 15456 //! Compute the image histogram.
philpem@5 15457 /**
philpem@5 15458 The histogram H of an image I is a 1D-function where H(x) is the number of
philpem@5 15459 occurences of the value x in I.
philpem@5 15460 \param nblevels = Number of different levels of the computed histogram.
philpem@5 15461 For classical images, this value is 256. You should specify more levels
philpem@5 15462 if you are working with CImg<float> or images with high range of pixel values.
philpem@5 15463 \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
philpem@5 15464 won't be counted.
philpem@5 15465 \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
philpem@5 15466 won't be counted.
philpem@5 15467 \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum
philpem@5 15468 pixel values of the current image, then uses these values for the histogram computation.
philpem@5 15469 \result The histogram is returned as a 1D CImg<float> image H, having a size of (nblevels,1,1,1) such that
philpem@5 15470 H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I.
philpem@5 15471 \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images
philpem@5 15472 are not multi-dimensional.
philpem@5 15473 **/
philpem@5 15474 CImg<T>& histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
philpem@5 15475 return get_histogram(nblevels,val_min,val_max).transfer_to(*this);
philpem@5 15476 }
philpem@5 15477
philpem@5 15478 CImg<floatT> get_histogram(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
philpem@5 15479 if (is_empty()) return CImg<floatT>();
philpem@5 15480 if (!nblevels)
philpem@5 15481 throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels",
philpem@5 15482 pixel_type());
philpem@5 15483 T vmin = val_min, vmax = val_max;
philpem@5 15484 CImg<floatT> res(nblevels,1,1,1,0);
philpem@5 15485 if (vmin>=vmax && vmin==0) vmin = minmax(vmax);
philpem@5 15486 if (vmin<vmax) cimg_for(*this,ptr,T) {
philpem@5 15487 const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
philpem@5 15488 if (pos>=0 && pos<(int)nblevels) ++res[pos];
philpem@5 15489 } else res[0]+=size();
philpem@5 15490 return res;
philpem@5 15491 }
philpem@5 15492
philpem@5 15493 //! Compute the histogram-equalized version of the instance image.
philpem@5 15494 /**
philpem@5 15495 The histogram equalization is a classical image processing algorithm that enhances the image contrast
philpem@5 15496 by expanding its histogram.
philpem@5 15497 \param nblevels = Number of different levels of the computed histogram.
philpem@5 15498 For classical images, this value is 256. You should specify more levels
philpem@5 15499 if you are working with CImg<float> or images with high range of pixel values.
philpem@5 15500 \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min
philpem@5 15501 won't be changed.
philpem@5 15502 \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max
philpem@5 15503 won't be changed.
philpem@5 15504 \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image.
philpem@5 15505 \return A new image with same size is returned, where pixels have been equalized.
philpem@5 15506 **/
philpem@5 15507 CImg<T>& equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) {
philpem@5 15508 if (is_empty()) return *this;
philpem@5 15509 T vmin = val_min, vmax = val_max;
philpem@5 15510 if (vmin==vmax && vmin==0) vmin = minmax(vmax);
philpem@5 15511 if (vmin<vmax) {
philpem@5 15512 CImg<floatT> hist = get_histogram(nblevels,vmin,vmax);
philpem@5 15513 float cumul = 0;
philpem@5 15514 cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; }
philpem@5 15515 cimg_for(*this,ptr,T) {
philpem@5 15516 const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin));
philpem@5 15517 if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size());
philpem@5 15518 }
philpem@5 15519 }
philpem@5 15520 return *this;
philpem@5 15521 }
philpem@5 15522
philpem@5 15523 CImg<T> get_equalize(const unsigned int nblevels, const T val_min=(T)0, const T val_max=(T)0) const {
philpem@5 15524 return (+*this).equalize(nblevels,val_min,val_max);
philpem@5 15525 }
philpem@5 15526
philpem@5 15527 //! Get a label map of disconnected regions with same intensities.
philpem@5 15528 CImg<T>& label_regions() {
philpem@5 15529 return get_label_regions().transfer_to(*this);
philpem@5 15530 }
philpem@5 15531
philpem@5 15532 CImg<uintT> get_label_regions() const {
philpem@5 15533 #define _cimg_get_label_test(p,q) { \
philpem@5 15534 flag = true; \
philpem@5 15535 const T *ptr1 = ptr(x,y) + siz, *ptr2 = ptr(p,q) + siz; \
philpem@5 15536 for (unsigned int i = dim; flag && i; --i) { ptr1-=wh; ptr2-=wh; flag = (*ptr1==*ptr2); } \
philpem@5 15537 }
philpem@5 15538 if (depth>1)
philpem@5 15539 throw CImgInstanceException("CImg<%s>::label_regions() : Instance image must be a 2D image");
philpem@5 15540 CImg<uintT> res(width,height,depth,1,0);
philpem@5 15541 unsigned int label = 1;
philpem@5 15542 const unsigned int wh = width*height, siz = width*height*dim;
philpem@5 15543 const int W1 = dimx()-1, H1 = dimy()-1;
philpem@5 15544 bool flag;
philpem@5 15545 cimg_forXY(*this,x,y) {
philpem@5 15546 bool done = false;
philpem@5 15547 if (y) {
philpem@5 15548 _cimg_get_label_test(x,y-1);
philpem@5 15549 if (flag) {
philpem@5 15550 const unsigned int lab = (res(x,y) = res(x,y-1));
philpem@5 15551 done = true;
philpem@5 15552 if (x && res(x-1,y)!=lab) {
philpem@5 15553 _cimg_get_label_test(x-1,y);
philpem@5 15554 if (flag) {
philpem@5 15555 const unsigned int lold = res(x-1,y), *const cptr = res.ptr(x,y);
philpem@5 15556 for (unsigned int *ptr = res.ptr(); ptr<cptr; ++ptr) if (*ptr==lold) *ptr = lab;
philpem@5 15557 }
philpem@5 15558 }
philpem@5 15559 }
philpem@5 15560 }
philpem@5 15561 if (x && !done) { _cimg_get_label_test(x-1,y); if (flag) { res(x,y) = res(x-1,y); done = true; }}
philpem@5 15562 if (!done) res(x,y) = label++;
philpem@5 15563 }
philpem@5 15564 { for (int y = H1; y>=0; --y) for (int x=W1; x>=0; --x) {
philpem@5 15565 bool done = false;
philpem@5 15566 if (y<H1) {
philpem@5 15567 _cimg_get_label_test(x,y+1);
philpem@5 15568 if (flag) {
philpem@5 15569 const unsigned int lab = (res(x,y) = res(x,y+1));
philpem@5 15570 done = true;
philpem@5 15571 if (x<W1 && res(x+1,y)!=lab) {
philpem@5 15572 _cimg_get_label_test(x+1,y);
philpem@5 15573 if (flag) {
philpem@5 15574 const unsigned int lold = res(x+1,y), *const cptr = res.ptr(x,y);
philpem@5 15575 for (unsigned int *ptr = res.ptr()+res.size()-1; ptr>cptr; --ptr) if (*ptr==lold) *ptr = lab;
philpem@5 15576 }
philpem@5 15577 }
philpem@5 15578 }
philpem@5 15579 }
philpem@5 15580 if (x<W1 && !done) { _cimg_get_label_test(x+1,y); if (flag) res(x,y) = res(x+1,y); done = true; }
philpem@5 15581 }}
philpem@5 15582 const unsigned int lab0 = res.max()+1;
philpem@5 15583 label = lab0;
philpem@5 15584 cimg_foroff(res,off) { // Relabel regions
philpem@5 15585 const unsigned int lab = res[off];
philpem@5 15586 if (lab<lab0) { cimg_for(res,ptr,unsigned int) if (*ptr==lab) *ptr = label; ++label; }
philpem@5 15587 }
philpem@5 15588 return (res-=lab0);
philpem@5 15589 }
philpem@5 15590
philpem@5 15591 //! Compute the scalar image of vector norms.
philpem@5 15592 /**
philpem@5 15593 When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each
philpem@5 15594 vector-valued pixel.
philpem@5 15595 \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf).
philpem@5 15596 \return A scalar-valued image CImg<float> with size (dimx(),dimy(),dimz(),1), where each pixel is the norm
philpem@5 15597 of the corresponding pixels in the original vector-valued image.
philpem@5 15598 **/
philpem@5 15599 CImg<T>& pointwise_norm(int norm_type=2) {
philpem@5 15600 return get_pointwise_norm(norm_type).transfer_to(*this);
philpem@5 15601 }
philpem@5 15602
philpem@5 15603 CImg<Tfloat> get_pointwise_norm(int norm_type=2) const {
philpem@5 15604 if (is_empty()) return *this;
philpem@5 15605 if (dim==1) return get_abs();
philpem@5 15606 CImg<Tfloat> res(width,height,depth);
philpem@5 15607 switch (norm_type) {
philpem@5 15608 case -1 : { // Linf norm
philpem@5 15609 cimg_forXYZ(*this,x,y,z) {
philpem@5 15610 Tfloat n = 0; cimg_forV(*this,v) {
philpem@5 15611 const Tfloat tmp = (Tfloat)cimg::abs((*this)(x,y,z,v));
philpem@5 15612 if (tmp>n) n=tmp; res(x,y,z) = n;
philpem@5 15613 }
philpem@5 15614 }
philpem@5 15615 } break;
philpem@5 15616 case 1 : { // L1 norm
philpem@5 15617 cimg_forXYZ(*this,x,y,z) {
philpem@5 15618 Tfloat n = 0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n;
philpem@5 15619 }
philpem@5 15620 } break;
philpem@5 15621 default : { // L2 norm
philpem@5 15622 cimg_forXYZ(*this,x,y,z) {
philpem@5 15623 Tfloat n = 0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (Tfloat)cimg_std::sqrt((double)n);
philpem@5 15624 }
philpem@5 15625 }
philpem@5 15626 }
philpem@5 15627 return res;
philpem@5 15628 }
philpem@5 15629
philpem@5 15630 //! Compute the image of normalized vectors.
philpem@5 15631 /**
philpem@5 15632 When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors
philpem@5 15633 (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization.
philpem@5 15634 \return A new vector-valued image with same size, where each vector-valued pixels have been normalized.
philpem@5 15635 **/
philpem@5 15636 CImg<T>& pointwise_orientation() {
philpem@5 15637 cimg_forXYZ(*this,x,y,z) {
philpem@5 15638 float n = 0;
philpem@5 15639 cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v));
philpem@5 15640 n = (float)cimg_std::sqrt(n);
philpem@5 15641 if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v) = (T)((*this)(x,y,z,v)/n);
philpem@5 15642 else cimg_forV(*this,v) (*this)(x,y,z,v) = 0;
philpem@5 15643 }
philpem@5 15644 return *this;
philpem@5 15645 }
philpem@5 15646
philpem@5 15647 CImg<Tfloat> get_pointwise_orientation() const {
philpem@5 15648 if (is_empty()) return *this;
philpem@5 15649 return CImg<Tfloat>(*this,false).pointwise_orientation();
philpem@5 15650 }
philpem@5 15651
philpem@5 15652 //! Split image into a list.
philpem@5 15653 CImgList<T> get_split(const char axis, const unsigned int nb=0) const {
philpem@5 15654 if (is_empty()) return CImgList<T>();
philpem@5 15655 CImgList<T> res;
philpem@5 15656 switch (cimg::uncase(axis)) {
philpem@5 15657 case 'x' : {
philpem@5 15658 if (nb>width)
philpem@5 15659 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.",
philpem@5 15660 pixel_type(),width,height,depth,dim,data,nb);
philpem@5 15661 res.assign(nb?nb:width);
philpem@5 15662 const unsigned int delta = (unsigned int)cimg::round((float)width/res.size,1);
philpem@5 15663 unsigned int l, x;
philpem@5 15664 for (l = 0, x = 0; l<res.size-1; ++l, x+=delta) res[l] = get_crop(x,0,0,0,x+delta-1,height-1,depth-1,dim-1);
philpem@5 15665 res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1);
philpem@5 15666 } break;
philpem@5 15667 case 'y' : {
philpem@5 15668 if (nb>height)
philpem@5 15669 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.",
philpem@5 15670 pixel_type(),width,height,depth,dim,data,nb);
philpem@5 15671 res.assign(nb?nb:height);
philpem@5 15672 const unsigned int delta = (unsigned int)cimg::round((float)height/res.size,1);
philpem@5 15673 unsigned int l, y;
philpem@5 15674 for (l = 0, y = 0; l<res.size-1; ++l, y+=delta) res[l] = get_crop(0,y,0,0,width-1,y+delta-1,depth-1,dim-1);
philpem@5 15675 res[res.size-1] = get_crop(0,y,0,0,width-1,height-1,depth-1,dim-1);
philpem@5 15676 } break;
philpem@5 15677 case 'z' : {
philpem@5 15678 if (nb>depth)
philpem@5 15679 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.",
philpem@5 15680 pixel_type(),width,height,depth,dim,data,nb);
philpem@5 15681 res.assign(nb?nb:depth);
philpem@5 15682 const unsigned int delta = (unsigned int)cimg::round((float)depth/res.size,1);
philpem@5 15683 unsigned int l, z;
philpem@5 15684 for (l = 0, z = 0; l<res.size-1; ++l, z+=delta) res[l] = get_crop(0,0,z,0,width-1,height-1,z+delta-1,dim-1);
philpem@5 15685 res[res.size-1] = get_crop(0,0,z,0,width-1,height-1,depth-1,dim-1);
philpem@5 15686 } break;
philpem@5 15687 case 'v' : {
philpem@5 15688 if (nb>dim)
philpem@5 15689 throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.",
philpem@5 15690 pixel_type(),width,height,depth,dim,data,nb);
philpem@5 15691 res.assign(nb?nb:dim);
philpem@5 15692 const unsigned int delta = (unsigned int)cimg::round((float)dim/res.size,1);
philpem@5 15693 unsigned int l, v;
philpem@5 15694 for (l = 0, v = 0; l<res.size-1; ++l, v+=delta) res[l] = get_crop(0,0,0,v,width-1,height-1,depth-1,v+delta-1);
philpem@5 15695 res[res.size-1] = get_crop(0,0,0,v,width-1,height-1,depth-1,dim-1);
philpem@5 15696 } break;
philpem@5 15697 default :
philpem@5 15698 throw CImgArgumentException("CImg<%s>::get_split() : Unknow axis '%c', must be 'x','y','z' or 'v'",
philpem@5 15699 pixel_type(),axis);
philpem@5 15700 }
philpem@5 15701 return res;
philpem@5 15702 }
philpem@5 15703
philpem@5 15704 // Split image into a list of vectors, according to a given splitting value.
philpem@5 15705 CImgList<T> get_split(const T value, const bool keep_values, const bool shared) const {
philpem@5 15706 CImgList<T> res;
philpem@5 15707 const T *ptr0 = data, *const ptr_end = data + size();
philpem@5 15708 while (ptr0<ptr_end) {
philpem@5 15709 const T *ptr1 = ptr0;
philpem@5 15710 while (ptr1<ptr_end && *ptr1==value) ++ptr1;
philpem@5 15711 const unsigned int siz0 = ptr1 - ptr0;
philpem@5 15712 if (siz0 && keep_values) res.insert(CImg<T>(ptr0,1,siz0,1,1,shared));
philpem@5 15713 ptr0 = ptr1;
philpem@5 15714 while (ptr1<ptr_end && *ptr1!=value) ++ptr1;
philpem@5 15715 const unsigned int siz1 = ptr1 - ptr0;
philpem@5 15716 if (siz1) res.insert(CImg<T>(ptr0,1,siz1,1,1,shared),~0U,shared);
philpem@5 15717 ptr0 = ptr1;
philpem@5 15718 }
philpem@5 15719 return res;
philpem@5 15720 }
philpem@5 15721
philpem@5 15722 //! Append an image to another one.
philpem@5 15723 CImg<T>& append(const CImg<T>& img, const char axis, const char align='p') {
philpem@5 15724 if (!img) return *this;
philpem@5 15725 if (is_empty()) return (*this=img);
philpem@5 15726 return get_append(img,axis,align).transfer_to(*this);
philpem@5 15727 }
philpem@5 15728
philpem@5 15729 CImg<T> get_append(const CImg<T>& img, const char axis, const char align='p') const {
philpem@5 15730 if (!img) return *this;
philpem@5 15731 if (is_empty()) return img;
philpem@5 15732 CImgList<T> temp(2);
philpem@5 15733 temp[0].width = width; temp[0].height = height; temp[0].depth = depth;
philpem@5 15734 temp[0].dim = dim; temp[0].data = data;
philpem@5 15735 temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth;
philpem@5 15736 temp[1].dim = img.dim; temp[1].data = img.data;
philpem@5 15737 const CImg<T> res = temp.get_append(axis,align);
philpem@5 15738 temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0;
philpem@5 15739 temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0;
philpem@5 15740 return res;
philpem@5 15741 }
philpem@5 15742
philpem@5 15743 //! Compute the list of images, corresponding to the XY-gradients of an image.
philpem@5 15744 /**
philpem@5 15745 \param scheme = Numerical scheme used for the gradient computation :
philpem@5 15746 - -1 = Backward finite differences
philpem@5 15747 - 0 = Centered finite differences
philpem@5 15748 - 1 = Forward finite differences
philpem@5 15749 - 2 = Using Sobel masks
philpem@5 15750 - 3 = Using rotation invariant masks
philpem@5 15751 - 4 = Using Deriche recusrsive filter.
philpem@5 15752 **/
philpem@5 15753 CImgList<Tfloat> get_gradient(const char *const axes=0, const int scheme=3) const {
philpem@5 15754 CImgList<Tfloat> grad(2,width,height,depth,dim);
philpem@5 15755 bool threed = false;
philpem@5 15756 if (axes) {
philpem@5 15757 for (unsigned int a = 0; axes[a]; ++a) {
philpem@5 15758 const char axis = cimg::uncase(axes[a]);
philpem@5 15759 switch (axis) {
philpem@5 15760 case 'x' : case 'y' : break;
philpem@5 15761 case 'z' : threed = true; break;
philpem@5 15762 default :
philpem@5 15763 throw CImgArgumentException("CImg<%s>::get_gradient() : Unknown specified axis '%c'.",
philpem@5 15764 pixel_type(),axis);
philpem@5 15765 }
philpem@5 15766 }
philpem@5 15767 } else threed = (depth>1);
philpem@5 15768 if (threed) {
philpem@5 15769 grad.insert(1); grad[2].assign(width,height,depth,dim);
philpem@5 15770 switch (scheme) { // Compute 3D gradient
philpem@5 15771 case -1 : { // backward finite differences
philpem@5 15772 CImg_3x3x3(I,T);
philpem@5 15773 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
philpem@5 15774 grad[0](x,y,z,k) = (Tfloat)Iccc - Ipcc;
philpem@5 15775 grad[1](x,y,z,k) = (Tfloat)Iccc - Icpc;
philpem@5 15776 grad[2](x,y,z,k) = (Tfloat)Iccc - Iccp;
philpem@5 15777 }
philpem@5 15778 } break;
philpem@5 15779 case 1 : { // forward finite differences
philpem@5 15780 CImg_2x2x2(I,T);
philpem@5 15781 cimg_forV(*this,k) cimg_for2x2x2(*this,x,y,z,k,I) {
philpem@5 15782 grad[0](x,y,z,k) = (Tfloat)Incc - Iccc;
philpem@5 15783 grad[1](x,y,z,k) = (Tfloat)Icnc - Iccc;
philpem@5 15784 grad[2](x,y,z,k) = (Tfloat)Iccn - Iccc;
philpem@5 15785 }
philpem@5 15786 } break;
philpem@5 15787 case 4 : { // using Deriche filter with low standard variation
philpem@5 15788 grad[0] = get_deriche(0,1,'x');
philpem@5 15789 grad[1] = get_deriche(0,1,'y');
philpem@5 15790 grad[2] = get_deriche(0,1,'z');
philpem@5 15791 } break;
philpem@5 15792 default : { // central finite differences
philpem@5 15793 CImg_3x3x3(I,T);
philpem@5 15794 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
philpem@5 15795 grad[0](x,y,z,k) = 0.5f*((Tfloat)Incc - Ipcc);
philpem@5 15796 grad[1](x,y,z,k) = 0.5f*((Tfloat)Icnc - Icpc);
philpem@5 15797 grad[2](x,y,z,k) = 0.5f*((Tfloat)Iccn - Iccp);
philpem@5 15798 }
philpem@5 15799 }
philpem@5 15800 }
philpem@5 15801 } else switch (scheme) { // Compute 2D-gradient
philpem@5 15802 case -1 : { // backward finite differences
philpem@5 15803 CImg_3x3(I,T);
philpem@5 15804 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
philpem@5 15805 grad[0](x,y,z,k) = (Tfloat)Icc - Ipc;
philpem@5 15806 grad[1](x,y,z,k) = (Tfloat)Icc - Icp;
philpem@5 15807 }
philpem@5 15808 } break;
philpem@5 15809 case 1 : { // forward finite differences
philpem@5 15810 CImg_2x2(I,T);
philpem@5 15811 cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) {
philpem@5 15812 grad[0](x,y,0,k) = (Tfloat)Inc - Icc;
philpem@5 15813 grad[1](x,y,z,k) = (Tfloat)Icn - Icc;
philpem@5 15814 }
philpem@5 15815 } break;
philpem@5 15816 case 2 : { // using Sobel mask
philpem@5 15817 CImg_3x3(I,T);
philpem@5 15818 const Tfloat a = 1, b = 2;
philpem@5 15819 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
philpem@5 15820 grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
philpem@5 15821 grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
philpem@5 15822 }
philpem@5 15823 } break;
philpem@5 15824 case 3 : { // using rotation invariant mask
philpem@5 15825 CImg_3x3(I,T);
philpem@5 15826 const Tfloat a = (Tfloat)(0.25f*(2-cimg_std::sqrt(2.0f))), b = (Tfloat)(0.5f*(cimg_std::sqrt(2.0f)-1));
philpem@5 15827 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
philpem@5 15828 grad[0](x,y,z,k) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn;
philpem@5 15829 grad[1](x,y,z,k) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn;
philpem@5 15830 }
philpem@5 15831 } break;
philpem@5 15832 case 4 : { // using Deriche filter with low standard variation
philpem@5 15833 grad[0] = get_deriche(0,1,'x');
philpem@5 15834 grad[1] = get_deriche(0,1,'y');
philpem@5 15835 } break;
philpem@5 15836 default : { // central finite differences
philpem@5 15837 CImg_3x3(I,T);
philpem@5 15838 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) {
philpem@5 15839 grad[0](x,y,z,k) = 0.5f*((Tfloat)Inc - Ipc);
philpem@5 15840 grad[1](x,y,z,k) = 0.5f*((Tfloat)Icn - Icp);
philpem@5 15841 }
philpem@5 15842 }
philpem@5 15843 }
philpem@5 15844 if (!axes) return grad;
philpem@5 15845 CImgList<Tfloat> res;
philpem@5 15846 for (unsigned int l = 0; axes[l]; ++l) {
philpem@5 15847 const char axis = cimg::uncase(axes[l]);
philpem@5 15848 switch (axis) {
philpem@5 15849 case 'x' : res.insert(grad[0]); break;
philpem@5 15850 case 'y' : res.insert(grad[1]); break;
philpem@5 15851 case 'z' : res.insert(grad[2]); break;
philpem@5 15852 }
philpem@5 15853 }
philpem@5 15854 grad.assign();
philpem@5 15855 return res;
philpem@5 15856 }
philpem@5 15857
philpem@5 15858 //! Compute the structure tensor field of an image.
philpem@5 15859 CImg<T>& structure_tensor(const bool central_scheme=false) {
philpem@5 15860 return get_structure_tensor(central_scheme).transfer_to(*this);
philpem@5 15861 }
philpem@5 15862
philpem@5 15863 CImg<Tfloat> get_structure_tensor(const bool central_scheme=false) const {
philpem@5 15864 if (is_empty()) return *this;
philpem@5 15865 CImg<Tfloat> res;
philpem@5 15866 if (depth>1) { // 3D version
philpem@5 15867 res.assign(width,height,depth,6,0);
philpem@5 15868 CImg_3x3x3(I,T);
philpem@5 15869 if (central_scheme) cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // classical central finite differences
philpem@5 15870 const Tfloat
philpem@5 15871 ix = 0.5f*((Tfloat)Incc - Ipcc),
philpem@5 15872 iy = 0.5f*((Tfloat)Icnc - Icpc),
philpem@5 15873 iz = 0.5f*((Tfloat)Iccn - Iccp);
philpem@5 15874 res(x,y,z,0)+=ix*ix;
philpem@5 15875 res(x,y,z,1)+=ix*iy;
philpem@5 15876 res(x,y,z,2)+=ix*iz;
philpem@5 15877 res(x,y,z,3)+=iy*iy;
philpem@5 15878 res(x,y,z,4)+=iy*iz;
philpem@5 15879 res(x,y,z,5)+=iz*iz;
philpem@5 15880 } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { // Precise forward/backward finite differences
philpem@5 15881 const Tfloat
philpem@5 15882 ixf = (Tfloat)Incc - Iccc, ixb = (Tfloat)Iccc - Ipcc,
philpem@5 15883 iyf = (Tfloat)Icnc - Iccc, iyb = (Tfloat)Iccc - Icpc,
philpem@5 15884 izf = (Tfloat)Iccn - Iccc, izb = (Tfloat)Iccc - Iccp;
philpem@5 15885 res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb);
philpem@5 15886 res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb);
philpem@5 15887 res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb);
philpem@5 15888 res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb);
philpem@5 15889 res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb);
philpem@5 15890 res(x,y,z,5) += 0.5f*(izf*izf + izb*izb);
philpem@5 15891 }
philpem@5 15892 } else { // 2D version
philpem@5 15893 res.assign(width,height,depth,3,0);
philpem@5 15894 CImg_3x3(I,T);
philpem@5 15895 if (central_scheme) cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // classical central finite differences
philpem@5 15896 const Tfloat
philpem@5 15897 ix = 0.5f*((Tfloat)Inc - Ipc),
philpem@5 15898 iy = 0.5f*((Tfloat)Icn - Icp);
philpem@5 15899 res(x,y,0,0)+=ix*ix;
philpem@5 15900 res(x,y,0,1)+=ix*iy;
philpem@5 15901 res(x,y,0,2)+=iy*iy;
philpem@5 15902 } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { // Precise forward/backward finite differences
philpem@5 15903 const Tfloat
philpem@5 15904 ixf = (Tfloat)Inc - Icc, ixb = (Tfloat)Icc - Ipc,
philpem@5 15905 iyf = (Tfloat)Icn - Icc, iyb = (Tfloat)Icc - Icp;
philpem@5 15906 res(x,y,0,0) += 0.5f*(ixf*ixf+ixb*ixb);
philpem@5 15907 res(x,y,0,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb);
philpem@5 15908 res(x,y,0,2) += 0.5f*(iyf*iyf+iyb*iyb);
philpem@5 15909 }
philpem@5 15910 }
philpem@5 15911 return res;
philpem@5 15912 }
philpem@5 15913
philpem@5 15914 //! Get components of the Hessian matrix of an image.
philpem@5 15915 CImgList<Tfloat> get_hessian(const char *const axes=0) const {
philpem@5 15916 const char *naxes = axes, *const def_axes2d = "xxxyyy", *const def_axes3d = "xxxyxzyyyzzz";
philpem@5 15917 if (!axes) naxes = depth>1?def_axes3d:def_axes2d;
philpem@5 15918 CImgList<Tfloat> res;
philpem@5 15919 const int lmax = cimg::strlen(naxes);
philpem@5 15920 if (lmax%2)
philpem@5 15921 throw CImgArgumentException("CImg<%s>::get_hessian() : Incomplete parameter axes = '%s'.",
philpem@5 15922 pixel_type(),naxes);
philpem@5 15923 res.assign(lmax/2,width,height,depth,dim);
philpem@5 15924 if (!cimg::strcasecmp(naxes,def_axes3d)) { // Default 3D version
philpem@5 15925 CImg_3x3x3(I,T);
philpem@5 15926 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
philpem@5 15927 res[0](x,y,z,k) = (Tfloat)Ipcc + Incc - 2*Iccc; // Ixx
philpem@5 15928 res[1](x,y,z,k) = 0.25f*((Tfloat)Ippc + Innc - Ipnc - Inpc); // Ixy
philpem@5 15929 res[2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp); // Ixz
philpem@5 15930 res[3](x,y,z,k) = (Tfloat)Icpc + Icnc - 2*Iccc; // Iyy
philpem@5 15931 res[4](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp); // Iyz
philpem@5 15932 res[5](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc; // Izz
philpem@5 15933 }
philpem@5 15934 } else if (!cimg::strcasecmp(naxes,def_axes2d)) { // Default 2D version
philpem@5 15935 CImg_3x3(I,T);
philpem@5 15936 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
philpem@5 15937 res[0](x,y,0,k) = (Tfloat)Ipc + Inc - 2*Icc; // Ixx
philpem@5 15938 res[1](x,y,0,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp); // Ixy
philpem@5 15939 res[2](x,y,0,k) = (Tfloat)Icp + Icn - 2*Icc; // Iyy
philpem@5 15940 }
philpem@5 15941 } else for (int l = 0; l<lmax; ) { // Version with custom axes.
philpem@5 15942 const int l2 = l/2;
philpem@5 15943 char axis1 = naxes[l++], axis2 = naxes[l++];
philpem@5 15944 if (axis1>axis2) cimg::swap(axis1,axis2);
philpem@5 15945 bool valid_axis = false;
philpem@5 15946 if (axis1=='x' && axis2=='x') { // Ixx
philpem@5 15947 valid_axis = true; CImg_3x3(I,T);
philpem@5 15948 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Ipc + Inc - 2*Icc;
philpem@5 15949 }
philpem@5 15950 else if (axis1=='x' && axis2=='y') { // Ixy
philpem@5 15951 valid_axis = true; CImg_3x3(I,T);
philpem@5 15952 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipp + Inn - Ipn - Inp);
philpem@5 15953 }
philpem@5 15954 else if (axis1=='x' && axis2=='z') { // Ixz
philpem@5 15955 valid_axis = true; CImg_3x3x3(I,T);
philpem@5 15956 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Ipcp + Incn - Ipcn - Incp);
philpem@5 15957 }
philpem@5 15958 else if (axis1=='y' && axis2=='y') { // Iyy
philpem@5 15959 valid_axis = true; CImg_3x3(I,T);
philpem@5 15960 cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Icp + Icn - 2*Icc;
philpem@5 15961 }
philpem@5 15962 else if (axis1=='y' && axis2=='z') { // Iyz
philpem@5 15963 valid_axis = true; CImg_3x3x3(I,T);
philpem@5 15964 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = 0.25f*((Tfloat)Icpp + Icnn - Icpn - Icnp);
philpem@5 15965 }
philpem@5 15966 else if (axis1=='z' && axis2=='z') { // Izz
philpem@5 15967 valid_axis = true; CImg_3x3x3(I,T);
philpem@5 15968 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) res[l2](x,y,z,k) = (Tfloat)Iccn + Iccp - 2*Iccc;
philpem@5 15969 }
philpem@5 15970 else if (!valid_axis) throw CImgArgumentException("CImg<%s>::get_hessian() : Invalid parameter axes = '%s'.",
philpem@5 15971 pixel_type(),naxes);
philpem@5 15972 }
philpem@5 15973 return res;
philpem@5 15974 }
philpem@5 15975
philpem@5 15976 //! Compute distance function from 0-valued isophotes by the application of an Hamilton-Jacobi PDE.
philpem@5 15977 CImg<T>& distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) {
philpem@5 15978 if (is_empty()) return *this;
philpem@5 15979 CImg<Tfloat> veloc(*this);
philpem@5 15980 for (unsigned int iter = 0; iter<nb_iter; ++iter) {
philpem@5 15981 veloc.fill(0);
philpem@5 15982 if (depth>1) { // 3D version
philpem@5 15983 CImg_3x3x3(I,T);
philpem@5 15984 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)<band_size) {
philpem@5 15985 const Tfloat
philpem@5 15986 gx = 0.5f*((Tfloat)Incc - Ipcc),
philpem@5 15987 gy = 0.5f*((Tfloat)Icnc - Icpc),
philpem@5 15988 gz = 0.5f*((Tfloat)Iccn - Iccp),
philpem@5 15989 sgn = -cimg::sign((Tfloat)Iccc),
philpem@5 15990 ix = gx*sgn>0?(Tfloat)Incc - Iccc:(Tfloat)Iccc - Ipcc,
philpem@5 15991 iy = gy*sgn>0?(Tfloat)Icnc - Iccc:(Tfloat)Iccc - Icpc,
philpem@5 15992 iz = gz*sgn>0?(Tfloat)Iccn - Iccc:(Tfloat)Iccc - Iccp,
philpem@5 15993 ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy + gz*gz),
philpem@5 15994 ngx = gx/ng,
philpem@5 15995 ngy = gy/ng,
philpem@5 15996 ngz = gz/ng;
philpem@5 15997 veloc(x,y,z,k) = sgn*(ngx*ix + ngy*iy + ngz*iz - 1);
philpem@5 15998 }
philpem@5 15999 } else { // 2D version
philpem@5 16000 CImg_3x3(I,T);
philpem@5 16001 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)<band_size) {
philpem@5 16002 const Tfloat
philpem@5 16003 gx = 0.5f*((Tfloat)Inc - Ipc),
philpem@5 16004 gy = 0.5f*((Tfloat)Icn - Icp),
philpem@5 16005 sgn = -cimg::sign((Tfloat)Icc),
philpem@5 16006 ix = gx*sgn>0?(Tfloat)Inc - Icc:(Tfloat)Icc - Ipc,
philpem@5 16007 iy = gy*sgn>0?(Tfloat)Icn - Icc:(Tfloat)Icc - Icp,
philpem@5 16008 ng = 1e-5f + (Tfloat)cimg_std::sqrt(gx*gx + gy*gy),
philpem@5 16009 ngx = gx/ng,
philpem@5 16010 ngy = gy/ng;
philpem@5 16011 veloc(x,y,k) = sgn*(ngx*ix + ngy*iy - 1);
philpem@5 16012 }
philpem@5 16013 }
philpem@5 16014 float m, M = (float)veloc.maxmin(m), xdt = precision/(float)cimg::max(cimg::abs(m),cimg::abs(M));
philpem@5 16015 *this+=(veloc*=xdt);
philpem@5 16016 }
philpem@5 16017 return *this;
philpem@5 16018 }
philpem@5 16019
philpem@5 16020 CImg<Tfloat> get_distance_hamilton(const unsigned int nb_iter, const float band_size=0, const float precision=0.5f) const {
philpem@5 16021 return CImg<Tfloat>(*this,false).distance_hamilton(nb_iter,band_size,precision);
philpem@5 16022 }
philpem@5 16023
philpem@5 16024 //! Compute the Euclidean distance map to a shape of specified isovalue.
philpem@5 16025 CImg<T>& distance(const T isovalue,
philpem@5 16026 const float sizex=1, const float sizey=1, const float sizez=1,
philpem@5 16027 const bool compute_sqrt=true) {
philpem@5 16028 return get_distance(isovalue,sizex,sizey,sizez,compute_sqrt).transfer_to(*this);
philpem@5 16029 }
philpem@5 16030
philpem@5 16031 CImg<floatT> get_distance(const T isovalue,
philpem@5 16032 const float sizex=1, const float sizey=1, const float sizez=1,
philpem@5 16033 const bool compute_sqrt=true) const {
philpem@5 16034 if (is_empty()) return *this;
philpem@5 16035 const int dx = dimx(), dy = dimy(), dz = dimz();
philpem@5 16036 CImg<floatT> res(dx,dy,dz,dim);
philpem@5 16037 const float maxdist = (float)cimg_std::sqrt((float)dx*dx + dy*dy + dz*dz);
philpem@5 16038 cimg_forV(*this,k) {
philpem@5 16039 bool is_isophote = false;
philpem@5 16040
philpem@5 16041 if (depth>1) { // 3D version
philpem@5 16042 { cimg_forYZ(*this,y,z) {
philpem@5 16043 if ((*this)(0,y,z,k)==isovalue) { is_isophote = true; res(0,y,z,k) = 0; } else res(0,y,z,k) = maxdist;
philpem@5 16044 for (int x = 1; x<dx; ++x) if ((*this)(x,y,z,k)==isovalue) { is_isophote = true; res(x,y,z,k) = 0; }
philpem@5 16045 else res(x,y,z,k) = res(x-1,y,z,k) + sizex;
philpem@5 16046 { for (int x = dx-2; x>=0; --x) if (res(x+1,y,z,k)<res(x,y,z,k)) res(x,y,z,k) = res(x+1,y,z,k) + sizex; }
philpem@5 16047 }}
philpem@5 16048 if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
philpem@5 16049 CImg<floatT> tmp(cimg::max(dy,dz));
philpem@5 16050 CImg<intT> s(tmp.width), t(s.width);
philpem@5 16051 { cimg_forXZ(*this,x,z) {
philpem@5 16052 { cimg_forY(*this,y) tmp[y] = res(x,y,z,k); }
philpem@5 16053 int q = s[0] = t[0] = 0;
philpem@5 16054 { for (int y = 1; y<dy; ++y) {
philpem@5 16055 const float val = tmp[y], val2 = val*val;
philpem@5 16056 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizey)>_distance_f(t[q],y,val2,sizey)) --q;
philpem@5 16057 if (q<0) { q = 0; s[0] = y; }
philpem@5 16058 else {
philpem@5 16059 const int w = 1 + _distance_sep(s[q],y,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizey);
philpem@5 16060 if (w<dy) { s[++q] = y; t[q] = w; }
philpem@5 16061 }
philpem@5 16062 }}
philpem@5 16063 { for (int y = dy - 1; y>=0; --y) {
philpem@5 16064 res(x,y,z,k) = _distance_f(y,s[q],cimg::sqr(tmp[s[q]]),sizey);
philpem@5 16065 if (y==t[q]) --q;
philpem@5 16066 }}
philpem@5 16067 }}
philpem@5 16068 { cimg_forXY(*this,x,y) {
philpem@5 16069 { cimg_forZ(*this,z) tmp[z] = res(x,y,z,k); }
philpem@5 16070 int q = s[0] = t[0] = 0;
philpem@5 16071 { for (int z = 1; z<dz; ++z) {
philpem@5 16072 const float val = tmp[z];
philpem@5 16073 while (q>=0 && _distance_f(t(q),s[q],tmp[s[q]],sizez)>_distance_f(t[q],z,tmp[z],sizez)) --q;
philpem@5 16074 if (q<0) { q = 0; s[0] = z; }
philpem@5 16075 else {
philpem@5 16076 const int w = 1 + _distance_sep(s[q],z,(int)tmp[s[q]],(int)val,sizez);
philpem@5 16077 if (w<dz) { s[++q] = z; t[q] = w; }
philpem@5 16078 }
philpem@5 16079 }}
philpem@5 16080 { for (int z = dz - 1; z>=0; --z) {
philpem@5 16081 const float val = _distance_f(z,s[q],tmp[s[q]],sizez);
philpem@5 16082 res(x,y,z,k) = compute_sqrt?(float)cimg_std::sqrt(val):val;
philpem@5 16083 if (z==t[q]) --q;
philpem@5 16084 }}
philpem@5 16085 }}
philpem@5 16086 } else { // 2D version (with small optimizations)
philpem@5 16087 cimg_forX(*this,x) {
philpem@5 16088 const T *ptrs = ptr(x,0,0,k);
philpem@5 16089 float *ptrd = res.ptr(x,0,0,k), d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:maxdist;
philpem@5 16090 for (int y = 1; y<dy; ++y) { ptrs+=width; ptrd+=width; d = *ptrd = *ptrs==isovalue?(is_isophote=true),0:d+sizey; }
philpem@5 16091 { for (int y = dy - 2; y>=0; --y) { ptrd-=width; if (d<*ptrd) *ptrd = (d+=sizey); else d = *ptrd; }}
philpem@5 16092 }
philpem@5 16093 if (!is_isophote) { res.get_shared_channel(k).fill(cimg::type<float>::max()); continue; }
philpem@5 16094 CImg<floatT> tmp(dx);
philpem@5 16095 CImg<intT> s(dx), t(dx);
philpem@5 16096 cimg_forY(*this,y) {
philpem@5 16097 float *ptmp = tmp.ptr();
philpem@5 16098 cimg_std::memcpy(ptmp,res.ptr(0,y,0,k),sizeof(float)*dx);
philpem@5 16099 int q = s[0] = t[0] = 0;
philpem@5 16100 for (int x = 1; x<dx; ++x) {
philpem@5 16101 const float val = *(++ptmp), val2 = val*val;
philpem@5 16102 while (q>=0 && _distance_f(t[q],s[q],cimg::sqr(tmp[s[q]]),sizex)>_distance_f(t[q],x,val2,sizex)) --q;
philpem@5 16103 if (q<0) { q = 0; s[0] = x; }
philpem@5 16104 else {
philpem@5 16105 const int w = 1 + _distance_sep(s[q],x,(int)cimg::sqr(tmp[s[q]]),(int)val2,sizex);
philpem@5 16106 if (w<dx) { q++; s[q] = x; t[q] = w; }
philpem@5 16107 }
philpem@5 16108 }
philpem@5 16109 float *pres = res.ptr(0,y,0,k) + width;
philpem@5 16110 { for (int x = dx - 1; x>=0; --x) {
philpem@5 16111 const float val = _distance_f(x,s[q],cimg::sqr(tmp[s[q]]),sizex);
philpem@5 16112 *(--pres) = compute_sqrt?(float)cimg_std::sqrt(val):val;
philpem@5 16113 if (x==t[q]) --q;
philpem@5 16114 }}
philpem@5 16115 }
philpem@5 16116 }
philpem@5 16117 }
philpem@5 16118 return res;
philpem@5 16119 }
philpem@5 16120
philpem@5 16121 static float _distance_f(const int x, const int i, const float gi2, const float fact) {
philpem@5 16122 const float xmi = fact*((float)x - i);
philpem@5 16123 return xmi*xmi + gi2;
philpem@5 16124 }
philpem@5 16125 static int _distance_sep(const int i, const int u, const int gi2, const int gu2, const float fact) {
philpem@5 16126 const float fact2 = fact*fact;
philpem@5 16127 return (int)(fact2*(u*u - i*i) + gu2 - gi2)/(int)(2*fact2*(u - i));
philpem@5 16128 }
philpem@5 16129
philpem@5 16130 //! Compute minimal path in a graph, using the Dijkstra algorithm.
philpem@5 16131 /**
philpem@5 16132 \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance between two nodes (i,j).
philpem@5 16133 \param nb_nodes Number of graph nodes.
philpem@5 16134 \param starting_node Indice of the starting node.
philpem@5 16135 \param ending_node Indice of the ending node (set to ~0U to ignore ending node).
philpem@5 16136 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
philpem@5 16137 \return Array of distances of each node to the starting node.
philpem@5 16138 **/
philpem@5 16139 template<typename tf, typename t>
philpem@5 16140 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
philpem@5 16141 const unsigned int starting_node, const unsigned int ending_node,
philpem@5 16142 CImg<t>& previous) {
philpem@5 16143
philpem@5 16144 CImg<T> dist(1,nb_nodes,1,1,cimg::type<T>::max());
philpem@5 16145 dist(starting_node) = 0;
philpem@5 16146 previous.assign(1,nb_nodes,1,1,(t)-1);
philpem@5 16147 previous(starting_node) = (t)starting_node;
philpem@5 16148 CImg<uintT> Q(nb_nodes);
philpem@5 16149 cimg_forX(Q,u) Q(u) = u;
philpem@5 16150 cimg::swap(Q(starting_node),Q(0));
philpem@5 16151 unsigned int sizeQ = nb_nodes;
philpem@5 16152 while (sizeQ) {
philpem@5 16153 // Update neighbors from minimal vertex
philpem@5 16154 const unsigned int umin = Q(0);
philpem@5 16155 if (umin==ending_node) sizeQ = 0;
philpem@5 16156 else {
philpem@5 16157 const T dmin = dist(umin);
philpem@5 16158 const T infty = cimg::type<T>::max();
philpem@5 16159 for (unsigned int q=1; q<sizeQ; ++q) {
philpem@5 16160 const unsigned int v = Q(q);
philpem@5 16161 const T d = (T)distance(v,umin);
philpem@5 16162 if (d<infty) {
philpem@5 16163 const T alt = dmin + d;
philpem@5 16164 if (alt<dist(v)) {
philpem@5 16165 dist(v) = alt;
philpem@5 16166 previous(v) = (t)umin;
philpem@5 16167 const T distpos = dist(Q(q));
philpem@5 16168 for (unsigned int pos = q, par = 0; pos && distpos<dist(Q(par=(pos+1)/2-1)); pos=par) cimg::swap(Q(pos),Q(par));
philpem@5 16169 }
philpem@5 16170 }
philpem@5 16171 }
philpem@5 16172 // Remove minimal vertex from queue
philpem@5 16173 Q(0) = Q(--sizeQ);
philpem@5 16174 const T distpos = dist(Q(0));
philpem@5 16175 for (unsigned int pos = 0, left = 0, right = 0;
philpem@5 16176 ((right=2*(pos+1),(left=right-1))<sizeQ && distpos>dist(Q(left))) || (right<sizeQ && distpos>dist(Q(right)));) {
philpem@5 16177 if (right<sizeQ) {
philpem@5 16178 if (dist(Q(left))<dist(Q(right))) { cimg::swap(Q(pos),Q(left)); pos = left; }
philpem@5 16179 else { cimg::swap(Q(pos),Q(right)); pos = right; }
philpem@5 16180 } else { cimg::swap(Q(pos),Q(left)); pos = left; }
philpem@5 16181 }
philpem@5 16182 }
philpem@5 16183 }
philpem@5 16184 return dist;
philpem@5 16185 }
philpem@5 16186
philpem@5 16187 //! Return minimal path in a graph, using the Dijkstra algorithm.
philpem@5 16188 template<typename tf, typename t>
philpem@5 16189 static CImg<T> dijkstra(const tf& distance, const unsigned int nb_nodes,
philpem@5 16190 const unsigned int starting_node, const unsigned int ending_node=~0U) {
philpem@5 16191 CImg<uintT> foo;
philpem@5 16192 return dijkstra(distance,nb_nodes,starting_node,ending_node,foo);
philpem@5 16193 }
philpem@5 16194
philpem@5 16195 //! Return minimal path in a graph, using the Dijkstra algorithm.
philpem@5 16196 /**
philpem@5 16197 Instance image corresponds to the adjacency matrix of the graph.
philpem@5 16198 \param starting_node Indice of the starting node.
philpem@5 16199 \param previous Array that gives the previous node indice in the path to the starting node (optional parameter).
philpem@5 16200 \return Array of distances of each node to the starting node.
philpem@5 16201 **/
philpem@5 16202 template<typename t>
philpem@5 16203 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) {
philpem@5 16204 return get_dijkstra(starting_node,ending_node,previous).transfer_to(*this);
philpem@5 16205 }
philpem@5 16206
philpem@5 16207 template<typename t>
philpem@5 16208 CImg<T> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, CImg<t>& previous) const {
philpem@5 16209 if (width!=height || depth!=1 || dim!=1)
philpem@5 16210 throw CImgInstanceException("CImg<%s>::dijkstra() : Instance image (%u,%u,%u,%u,%p) is not a graph adjacency matrix",
philpem@5 16211 pixel_type(),width,height,depth,dim,data);
philpem@5 16212 return dijkstra(*this,width,starting_node,ending_node,previous);
philpem@5 16213 }
philpem@5 16214
philpem@5 16215 //! Return minimal path in a graph, using the Dijkstra algorithm.
philpem@5 16216 CImg<T>& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) {
philpem@5 16217 return get_dijkstra(starting_node,ending_node).transfer_to(*this);
philpem@5 16218 }
philpem@5 16219
philpem@5 16220 CImg<Tfloat> get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const {
philpem@5 16221 CImg<uintT> foo;
philpem@5 16222 return get_dijkstra(starting_node,ending_node,foo);
philpem@5 16223 }
philpem@5 16224
philpem@5 16225 //@}
philpem@5 16226 //-------------------------------------
philpem@5 16227 //
philpem@5 16228 //! \name Meshes and Triangulations
philpem@5 16229 //@{
philpem@5 16230 //-------------------------------------
philpem@5 16231
philpem@5 16232 //! Return a 3D centered cube.
philpem@5 16233 template<typename tf>
philpem@5 16234 static CImg<floatT> cube3d(CImgList<tf>& primitives, const float size=100) {
philpem@5 16235 const double s = size/2.0;
philpem@5 16236 primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
philpem@5 16237 return CImg<floatT>(8,3,1,1,
philpem@5 16238 -s,s,s,-s,-s,s,s,-s,
philpem@5 16239 -s,-s,s,s,-s,-s,s,s,
philpem@5 16240 -s,-s,-s,-s,s,s,s,s);
philpem@5 16241 }
philpem@5 16242
philpem@5 16243 //! Return a 3D centered cuboid.
philpem@5 16244 template<typename tf>
philpem@5 16245 static CImg<floatT> cuboid3d(CImgList<tf>& primitives, const float sizex=200,
philpem@5 16246 const float sizey=100, const float sizez=100) {
philpem@5 16247 const double sx = sizex/2.0, sy = sizey/2.0, sz = sizez/2.0;
philpem@5 16248 primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5);
philpem@5 16249 return CImg<floatT>(8,3,1,1,
philpem@5 16250 -sx,sx,sx,-sx,-sx,sx,sx,-sx,
philpem@5 16251 -sy,-sy,sy,sy,-sy,-sy,sy,sy,
philpem@5 16252 -sz,-sz,-sz,-sz,sz,sz,sz,sz);
philpem@5 16253 }
philpem@5 16254
philpem@5 16255 //! Return a 3D centered cone.
philpem@5 16256 template<typename tf>
philpem@5 16257 static CImg<floatT> cone3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
philpem@5 16258 const unsigned int subdivisions=24, const bool symetrize=false) {
philpem@5 16259 primitives.assign();
philpem@5 16260 if (!subdivisions) return CImg<floatT>();
philpem@5 16261 const double r = (double)radius, h = (double)height/2;
philpem@5 16262 CImgList<floatT> points(2,1,3,1,1,
philpem@5 16263 0.0,0.0,h,
philpem@5 16264 0.0,0.0,-h);
philpem@5 16265 const float delta = 360.0f/subdivisions, nh = symetrize?0:-(float)h;
philpem@5 16266 for (float angle = 0; angle<360; angle+=delta) {
philpem@5 16267 const float a = (float)(angle*cimg::valuePI/180);
philpem@5 16268 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),nh));
philpem@5 16269 }
philpem@5 16270 const unsigned int nbr = points.size-2;
philpem@5 16271 for (unsigned int p = 0; p<nbr; ++p) {
philpem@5 16272 const unsigned int curr = 2+p, next = 2+((p+1)%nbr);
philpem@5 16273 primitives.insert(CImg<tf>::vector(1,next,curr)).
philpem@5 16274 insert(CImg<tf>::vector(0,curr,next));
philpem@5 16275 }
philpem@5 16276 return points.get_append('x');
philpem@5 16277 }
philpem@5 16278
philpem@5 16279 //! Return a 3D centered cylinder.
philpem@5 16280 template<typename tf>
philpem@5 16281 static CImg<floatT> cylinder3d(CImgList<tf>& primitives, const float radius=50, const float height=100,
philpem@5 16282 const unsigned int subdivisions=24) {
philpem@5 16283 primitives.assign();
philpem@5 16284 if (!subdivisions) return CImg<floatT>();
philpem@5 16285 const double r = (double)radius, h = (double)height/2;
philpem@5 16286 CImgList<floatT> points(2,1,3,1,1,
philpem@5 16287 0.0,0.0,-h,
philpem@5 16288 0.0,0.0,h);
philpem@5 16289
philpem@5 16290 const float delta = 360.0f/subdivisions;
philpem@5 16291 for (float angle = 0; angle<360; angle+=delta) {
philpem@5 16292 const float a = (float)(angle*cimg::valuePI/180);
philpem@5 16293 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),-(float)h));
philpem@5 16294 points.insert(CImg<floatT>::vector((float)(r*cimg_std::cos(a)),(float)(r*cimg_std::sin(a)),(float)h));
philpem@5 16295 }
philpem@5 16296 const unsigned int nbr = (points.size-2)/2;
philpem@5 16297 for (unsigned int p = 0; p<nbr; ++p) {
philpem@5 16298 const unsigned int curr = 2+2*p, next = 2+(2*((p+1)%nbr));
philpem@5 16299 primitives.insert(CImg<tf>::vector(0,next,curr)).
philpem@5 16300 insert(CImg<tf>::vector(1,curr+1,next+1)).
philpem@5 16301 insert(CImg<tf>::vector(curr,next,next+1,curr+1));
philpem@5 16302 }
philpem@5 16303 return points.get_append('x');
philpem@5 16304 }
philpem@5 16305
philpem@5 16306 //! Return a 3D centered torus.
philpem@5 16307 template<typename tf>
philpem@5 16308 static CImg<floatT> torus3d(CImgList<tf>& primitives, const float radius1=100, const float radius2=30,
philpem@5 16309 const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) {
philpem@5 16310 primitives.assign();
philpem@5 16311 if (!subdivisions1 || !subdivisions2) return CImg<floatT>();
philpem@5 16312 CImgList<floatT> points;
philpem@5 16313 for (unsigned int v = 0; v<subdivisions1; ++v) {
philpem@5 16314 const float
philpem@5 16315 beta = (float)(v*2*cimg::valuePI/subdivisions1),
philpem@5 16316 xc = radius1*(float)cimg_std::cos(beta),
philpem@5 16317 yc = radius1*(float)cimg_std::sin(beta);
philpem@5 16318 for (unsigned int u=0; u<subdivisions2; ++u) {
philpem@5 16319 const float
philpem@5 16320 alpha = (float)(u*2*cimg::valuePI/subdivisions2),
philpem@5 16321 x = xc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::cos(beta)),
philpem@5 16322 y = yc + radius2*(float)(cimg_std::cos(alpha)*cimg_std::sin(beta)),
philpem@5 16323 z = radius2*(float)cimg_std::sin(alpha);
philpem@5 16324 points.insert(CImg<floatT>::vector(x,y,z));
philpem@5 16325 }
philpem@5 16326 }
philpem@5 16327 for (unsigned int vv = 0; vv<subdivisions1; ++vv) {
philpem@5 16328 const unsigned int nv = (vv+1)%subdivisions1;
philpem@5 16329 for (unsigned int uu = 0; uu<subdivisions2; ++uu) {
philpem@5 16330 const unsigned int nu = (uu+1)%subdivisions2, svv = subdivisions2*vv, snv = subdivisions2*nv;
philpem@5 16331 primitives.insert(CImg<tf>::vector(svv+nu,svv+uu,snv+uu));
philpem@5 16332 primitives.insert(CImg<tf>::vector(svv+nu,snv+uu,snv+nu));
philpem@5 16333 }
philpem@5 16334 }
philpem@5 16335 return points.get_append('x');
philpem@5 16336 }
philpem@5 16337
philpem@5 16338 //! Return a 3D centered XY plane.
philpem@5 16339 template<typename tf>
philpem@5 16340 static CImg<floatT> plane3d(CImgList<tf>& primitives, const float sizex=100, const float sizey=100,
philpem@5 16341 const unsigned int subdivisionsx=3, const unsigned int subdivisionsy=3,
philpem@5 16342 const bool double_sided=false) {
philpem@5 16343 primitives.assign();
philpem@5 16344 if (!subdivisionsx || !subdivisionsy) return CImg<floatT>();
philpem@5 16345 CImgList<floatT> points;
philpem@5 16346 const unsigned int w = subdivisionsx + 1, h = subdivisionsy + 1;
philpem@5 16347 const float w2 = subdivisionsx/2.0f, h2 = subdivisionsy/2.0f, fx = (float)sizex/w, fy = (float)sizey/h;
philpem@5 16348 for (unsigned int yy = 0; yy<h; ++yy)
philpem@5 16349 for (unsigned int xx = 0; xx<w; ++xx)
philpem@5 16350 points.insert(CImg<floatT>::vector(fx*(xx-w2),fy*(yy-h2),0));
philpem@5 16351 for (unsigned int y = 0; y<subdivisionsy; ++y) for (unsigned int x = 0; x<subdivisionsx; ++x) {
philpem@5 16352 const int off1 = x+y*w, off2 = x+1+y*w, off3 = x+1+(y+1)*w, off4 = x+(y+1)*w;
philpem@5 16353 primitives.insert(CImg<tf>::vector(off1,off4,off3,off2));
philpem@5 16354 if (double_sided) primitives.insert(CImg<tf>::vector(off1,off2,off3,off4));
philpem@5 16355 }
philpem@5 16356 return points.get_append('x');
philpem@5 16357 }
philpem@5 16358
philpem@5 16359 //! Return a 3D centered sphere.
philpem@5 16360 template<typename tf>
philpem@5 16361 static CImg<floatT> sphere3d(CImgList<tf>& primitives, const float radius=50, const unsigned int subdivisions=3) {
philpem@5 16362
philpem@5 16363 // Create initial icosahedron
philpem@5 16364 primitives.assign();
philpem@5 16365 if (!subdivisions) return CImg<floatT>();
philpem@5 16366 const double tmp = (1+cimg_std::sqrt(5.0f))/2, a = 1.0/cimg_std::sqrt(1+tmp*tmp), b = tmp*a;
philpem@5 16367 CImgList<floatT> points(12,1,3,1,1, b,a,0.0, -b,a,0.0, -b,-a,0.0, b,-a,0.0, a,0.0,b, a,0.0,-b,
philpem@5 16368 -a,0.0,-b, -a,0.0,b, 0.0,b,a, 0.0,-b,a, 0.0,-b,-a, 0.0,b,-a);
philpem@5 16369 primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6,
philpem@5 16370 8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3,
philpem@5 16371 5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2);
philpem@5 16372
philpem@5 16373 // Recurse subdivisions
philpem@5 16374 for (unsigned int i = 0; i<subdivisions; ++i) {
philpem@5 16375 const unsigned int L = primitives.size;
philpem@5 16376 for (unsigned int l = 0; l<L; ++l) {
philpem@5 16377 const unsigned int
philpem@5 16378 p0 = (unsigned int)primitives(0,0), p1 = (unsigned int)primitives(0,1), p2 = (unsigned int)primitives(0,2);
philpem@5 16379 const float
philpem@5 16380 x0 = points(p0,0), y0 = points(p0,1), z0 = points(p0,2),
philpem@5 16381 x1 = points(p1,0), y1 = points(p1,1), z1 = points(p1,2),
philpem@5 16382 x2 = points(p2,0), y2 = points(p2,1), z2 = points(p2,2),
philpem@5 16383 tnx0 = (x0+x1)/2, tny0 = (y0+y1)/2, tnz0 = (z0+z1)/2, nn0 = (float)cimg_std::sqrt(tnx0*tnx0+tny0*tny0+tnz0*tnz0),
philpem@5 16384 tnx1 = (x0+x2)/2, tny1 = (y0+y2)/2, tnz1 = (z0+z2)/2, nn1 = (float)cimg_std::sqrt(tnx1*tnx1+tny1*tny1+tnz1*tnz1),
philpem@5 16385 tnx2 = (x1+x2)/2, tny2 = (y1+y2)/2, tnz2 = (z1+z2)/2, nn2 = (float)cimg_std::sqrt(tnx2*tnx2+tny2*tny2+tnz2*tnz2),
philpem@5 16386 nx0 = tnx0/nn0, ny0 = tny0/nn0, nz0 = tnz0/nn0,
philpem@5 16387 nx1 = tnx1/nn1, ny1 = tny1/nn1, nz1 = tnz1/nn1,
philpem@5 16388 nx2 = tnx2/nn2, ny2 = tny2/nn2, nz2 = tnz2/nn2;
philpem@5 16389 int i0 = -1, i1 = -1, i2 = -1;
philpem@5 16390 cimglist_for(points,p) {
philpem@5 16391 const float x = (float)points(p,0), y = (float)points(p,1), z = (float)points(p,2);
philpem@5 16392 if (x==nx0 && y==ny0 && z==nz0) i0 = p;
philpem@5 16393 if (x==nx1 && y==ny1 && z==nz1) i1 = p;
philpem@5 16394 if (x==nx2 && y==ny2 && z==nz2) i2 = p;
philpem@5 16395 }
philpem@5 16396 if (i0<0) { points.insert(CImg<floatT>::vector(nx0,ny0,nz0)); i0 = points.size-1; }
philpem@5 16397 if (i1<0) { points.insert(CImg<floatT>::vector(nx1,ny1,nz1)); i1 = points.size-1; }
philpem@5 16398 if (i2<0) { points.insert(CImg<floatT>::vector(nx2,ny2,nz2)); i2 = points.size-1; }
philpem@5 16399 primitives.remove(0);
philpem@5 16400 primitives.insert(CImg<tf>::vector(p0,i0,i1)).
philpem@5 16401 insert(CImg<tf>::vector((tf)i0,(tf)p1,(tf)i2)).
philpem@5 16402 insert(CImg<tf>::vector((tf)i1,(tf)i2,(tf)p2)).
philpem@5 16403 insert(CImg<tf>::vector((tf)i1,(tf)i0,(tf)i2));
philpem@5 16404 }
philpem@5 16405 }
philpem@5 16406 return points.get_append('x')*=radius;
philpem@5 16407 }
philpem@5 16408
philpem@5 16409 //! Return a 3D centered ellipsoid.
philpem@5 16410 template<typename tf, typename t>
philpem@5 16411 static CImg<floatT> ellipsoid3d(CImgList<tf>& primitives, const CImg<t>& tensor,
philpem@5 16412 const unsigned int subdivisions=3) {
philpem@5 16413 primitives.assign();
philpem@5 16414 if (!subdivisions) return CImg<floatT>();
philpem@5 16415 typedef typename cimg::superset<t,float>::type tfloat;
philpem@5 16416 CImg<tfloat> S,V;
philpem@5 16417 tensor.symmetric_eigen(S,V);
philpem@5 16418 const tfloat l0 = S[0], l1 = S[1], l2 = S[2];
philpem@5 16419 CImg<floatT> points = sphere(primitives,subdivisions);
philpem@5 16420 cimg_forX(points,p) {
philpem@5 16421 points(p,0) = (float)(points(p,0)*l0);
philpem@5 16422 points(p,1) = (float)(points(p,1)*l1);
philpem@5 16423 points(p,2) = (float)(points(p,2)*l2);
philpem@5 16424 }
philpem@5 16425 V.transpose();
philpem@5 16426 points = V*points;
philpem@5 16427 return points;
philpem@5 16428 }
philpem@5 16429
philpem@5 16430 //! Return a 3D elevation object of the instance image.
philpem@5 16431 template<typename tf, typename tc, typename te>
philpem@5 16432 CImg<floatT> get_elevation3d(CImgList<tf>& primitives, CImgList<tc>& colors, const CImg<te>& elevation) const {
philpem@5 16433 primitives.assign();
philpem@5 16434 colors.assign();
philpem@5 16435 if (is_empty()) return *this;
philpem@5 16436 if (depth>1)
philpem@5 16437 throw CImgInstanceException("CImg<%s>::get_elevation3d() : Instance image (%u,%u,%u,%u,%p) is not a 2D image.",
philpem@5 16438 pixel_type(),width,height,depth,dim,data);
philpem@5 16439 if (!is_sameXY(elevation))
philpem@5 16440 throw CImgArgumentException("CImg<%s>::get_elevation3d() : Elevation image (%u,%u,%u,%u,%p) and instance image (%u,%u,%u,%u,%p) "
philpem@5 16441 "have different sizes.",pixel_type(),
philpem@5 16442 elevation.width,elevation.height,elevation.depth,elevation.dim,elevation.data,
philpem@5 16443 width,height,depth,dim,data,pixel_type());
philpem@5 16444 float m, M = (float)maxmin(m);
philpem@5 16445 if (M==m) ++M;
philpem@5 16446 const unsigned int w = width + 1, h = height + 1;
philpem@5 16447 CImg<floatT> points(w*h,3);
philpem@5 16448 cimg_forXY(*this,x,y) {
philpem@5 16449 const int yw = y*w, xpyw = x + yw, xpyww = xpyw + w;
philpem@5 16450 points(xpyw,0) = points(xpyw+1,0) = points(xpyww+1,0) = points(xpyww,0) = (float)x;
philpem@5 16451 points(xpyw,1) = points(xpyw+1,1) = points(xpyww+1,1) = points(xpyww,1) = (float)y;
philpem@5 16452 points(xpyw,2) = points(xpyw+1,2) = points(xpyww+1,2) = points(xpyww,2) = (float)elevation(x,y);
philpem@5 16453 primitives.insert(CImg<tf>::vector(xpyw,xpyw+1,xpyww+1,xpyww));
philpem@5 16454 const unsigned char
philpem@5 16455 r = (unsigned char)(((*this)(x,y,0) - m)*255/(M-m)),
philpem@5 16456 g = dim>1?(unsigned char)(((*this)(x,y,1) - m)*255/(M-m)):r,
philpem@5 16457 b = dim>2?(unsigned char)(((*this)(x,y,2) - m)*255/(M-m)):(dim>1?0:r);
philpem@5 16458 colors.insert(CImg<tc>::vector((tc)r,(tc)g,(tc)b));
philpem@5 16459 }
philpem@5 16460 return points;
philpem@5 16461 }
philpem@5 16462
philpem@5 16463 // Inner routine used by the Marching square algorithm.
philpem@5 16464 template<typename t>
philpem@5 16465 static int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
philpem@5 16466 const unsigned int x, const unsigned int nx) {
philpem@5 16467 switch (edge) {
philpem@5 16468 case 0 : return (int)indices1(x,0);
philpem@5 16469 case 1 : return (int)indices1(nx,1);
philpem@5 16470 case 2 : return (int)indices2(x,0);
philpem@5 16471 case 3 : return (int)indices1(x,1);
philpem@5 16472 }
philpem@5 16473 return 0;
philpem@5 16474 }
philpem@5 16475
philpem@5 16476 //! Polygonize an implicit 2D function by the marching squares algorithm.
philpem@5 16477 template<typename tf, typename tfunc>
philpem@5 16478 static CImg<floatT> marching_squares(CImgList<tf>& primitives, const tfunc& func, const float isovalue,
philpem@5 16479 const float x0, const float y0,
philpem@5 16480 const float x1, const float y1,
philpem@5 16481 const float resx, const float resy) {
philpem@5 16482 static unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 };
philpem@5 16483 static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 },
philpem@5 16484 { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 },
philpem@5 16485 { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 },
philpem@5 16486 { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } };
philpem@5 16487 const unsigned int
philpem@5 16488 nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
philpem@5 16489 ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1;
philpem@5 16490 if (!nxm1 || !nym1) return CImg<floatT>();
philpem@5 16491
philpem@5 16492 primitives.assign();
philpem@5 16493 CImgList<floatT> points;
philpem@5 16494 CImg<intT> indices1(nx,1,1,2,-1), indices2(nx,1,1,2);
philpem@5 16495 CImg<floatT> values1(nx), values2(nx);
philpem@5 16496 float X = 0, Y = 0, nX = 0, nY = 0;
philpem@5 16497
philpem@5 16498 // Fill first line with values
philpem@5 16499 cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; }
philpem@5 16500
philpem@5 16501 // Run the marching squares algorithm
philpem@5 16502 Y = y0; nY = Y + resy;
philpem@5 16503 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) {
philpem@5 16504 X = x0; nX = X + resx;
philpem@5 16505 indices2.fill(-1);
philpem@5 16506 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) {
philpem@5 16507
philpem@5 16508 // Determine cube configuration
philpem@5 16509 const float
philpem@5 16510 val0 = values1(xi), val1 = values1(nxi),
philpem@5 16511 val2 = values2(nxi) = (float)func(nX,nY),
philpem@5 16512 val3 = values2(xi) = (float)func(X,nY);
philpem@5 16513
philpem@5 16514 const unsigned int configuration = (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0),
philpem@5 16515 edge = edges[configuration];
philpem@5 16516
philpem@5 16517 // Compute intersection points
philpem@5 16518 if (edge) {
philpem@5 16519 if ((edge&1) && indices1(xi,0)<0) {
philpem@5 16520 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
philpem@5 16521 indices1(xi,0) = points.size;
philpem@5 16522 points.insert(CImg<floatT>::vector(Xi,Y));
philpem@5 16523 }
philpem@5 16524 if ((edge&2) && indices1(nxi,1)<0) {
philpem@5 16525 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
philpem@5 16526 indices1(nxi,1) = points.size;
philpem@5 16527 points.insert(CImg<floatT>::vector(nX,Yi));
philpem@5 16528 }
philpem@5 16529 if ((edge&4) && indices2(xi,0)<0) {
philpem@5 16530 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
philpem@5 16531 indices2(xi,0) = points.size;
philpem@5 16532 points.insert(CImg<floatT>::vector(Xi,nY));
philpem@5 16533 }
philpem@5 16534 if ((edge&8) && indices1(xi,1)<0) {
philpem@5 16535 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
philpem@5 16536 indices1(xi,1) = points.size;
philpem@5 16537 points.insert(CImg<floatT>::vector(X,Yi));
philpem@5 16538 }
philpem@5 16539
philpem@5 16540 // Create segments
philpem@5 16541 for (int *segment = segments[configuration]; *segment!=-1; ) {
philpem@5 16542 const unsigned int p0 = *(segment++), p1 = *(segment++);
philpem@5 16543 const tf
philpem@5 16544 i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)),
philpem@5 16545 i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi));
philpem@5 16546 primitives.insert(CImg<tf>::vector(i0,i1));
philpem@5 16547 }
philpem@5 16548 }
philpem@5 16549 }
philpem@5 16550 values1.swap(values2);
philpem@5 16551 indices1.swap(indices2);
philpem@5 16552 }
philpem@5 16553 return points.get_append('x');
philpem@5 16554 }
philpem@5 16555
philpem@5 16556 // Inner routine used by the Marching cube algorithm.
philpem@5 16557 template<typename t>
philpem@5 16558 static int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2,
philpem@5 16559 const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) {
philpem@5 16560 switch (edge) {
philpem@5 16561 case 0 : return indices1(x,y,0);
philpem@5 16562 case 1 : return indices1(nx,y,1);
philpem@5 16563 case 2 : return indices1(x,ny,0);
philpem@5 16564 case 3 : return indices1(x,y,1);
philpem@5 16565 case 4 : return indices2(x,y,0);
philpem@5 16566 case 5 : return indices2(nx,y,1);
philpem@5 16567 case 6 : return indices2(x,ny,0);
philpem@5 16568 case 7 : return indices2(x,y,1);
philpem@5 16569 case 8 : return indices1(x,y,2);
philpem@5 16570 case 9 : return indices1(nx,y,2);
philpem@5 16571 case 10 : return indices1(nx,ny,2);
philpem@5 16572 case 11 : return indices1(x,ny,2);
philpem@5 16573 }
philpem@5 16574 return 0;
philpem@5 16575 }
philpem@5 16576
philpem@5 16577 //! Polygonize an implicit function
philpem@5 16578 // This function uses the Marching Cubes Tables published on the web page :
philpem@5 16579 // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/
philpem@5 16580 template<typename tf, typename tfunc>
philpem@5 16581 static CImg<floatT> marching_cubes(CImgList<tf>& primitives,
philpem@5 16582 const tfunc& func, const float isovalue,
philpem@5 16583 const float x0, const float y0, const float z0,
philpem@5 16584 const float x1, const float y1, const float z1,
philpem@5 16585 const float resx, const float resy, const float resz,
philpem@5 16586 const bool invert_faces=false) {
philpem@5 16587
philpem@5 16588 static unsigned int edges[256] = {
philpem@5 16589 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
philpem@5 16590 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
philpem@5 16591 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
philpem@5 16592 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
philpem@5 16593 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
philpem@5 16594 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
philpem@5 16595 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
philpem@5 16596 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
philpem@5 16597 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
philpem@5 16598 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
philpem@5 16599 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
philpem@5 16600 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
philpem@5 16601 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
philpem@5 16602 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
philpem@5 16603 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
philpem@5 16604 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 };
philpem@5 16605
philpem@5 16606 static int triangles[256][16] =
philpem@5 16607 {{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16608 { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16609 { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16610 { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16611 { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16612 { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16613 { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16614 { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16615 { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16616 { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16617 { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16618 { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
philpem@5 16619 { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16620 { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 },
philpem@5 16621 { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 },
philpem@5 16622 { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16623 { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16624 { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16625 { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16626 { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 },
philpem@5 16627 { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16628 { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 },
philpem@5 16629 { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 },
philpem@5 16630 { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16631 { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16632 { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16633 { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 },
philpem@5 16634 { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16635 { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
philpem@5 16636 { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16637 { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 },
philpem@5 16638 { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16639 { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16640 { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16641 { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16642 { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 },
philpem@5 16643 { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16644 { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 },
philpem@5 16645 { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 },
philpem@5 16646 { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16647 { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16648 { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 },
philpem@5 16649 { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 },
philpem@5 16650 { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 },
philpem@5 16651 { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 },
philpem@5 16652 { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 },
philpem@5 16653 { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 },
philpem@5 16654 { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 },
philpem@5 16655 { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16656 { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 },
philpem@5 16657 { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 },
philpem@5 16658 { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16659 { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 },
philpem@5 16660 { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 },
philpem@5 16661 { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
philpem@5 16662 { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16663 { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 },
philpem@5 16664 { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16665 { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 },
philpem@5 16666 { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16667 { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 },
philpem@5 16668 { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 },
philpem@5 16669 { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16670 { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16671 { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16672 { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16673 { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16674 { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 },
philpem@5 16675 { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16676 { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 },
philpem@5 16677 { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 },
philpem@5 16678 { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16679 { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16680 { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 },
philpem@5 16681 { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 },
philpem@5 16682 { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 },
philpem@5 16683 { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16684 { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16685 { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16686 { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16687 { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16688 { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 },
philpem@5 16689 { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 },
philpem@5 16690 { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 },
philpem@5 16691 { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 },
philpem@5 16692 { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 },
philpem@5 16693 { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 },
philpem@5 16694 { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 },
philpem@5 16695 { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 },
philpem@5 16696 { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16697 { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 },
philpem@5 16698 { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 },
philpem@5 16699 { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16700 { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16701 { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 },
philpem@5 16702 { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16703 { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16704 { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 },
philpem@5 16705 { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 },
philpem@5 16706 { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 },
philpem@5 16707 { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 },
philpem@5 16708 { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 },
philpem@5 16709 { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16710 { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16711 { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 },
philpem@5 16712 { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 },
philpem@5 16713 { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 },
philpem@5 16714 { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16715 { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16716 { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 },
philpem@5 16717 { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16718 { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16719 { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 },
philpem@5 16720 { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 },
philpem@5 16721 { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 },
philpem@5 16722 { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 },
philpem@5 16723 { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 },
philpem@5 16724 { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16725 { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 },
philpem@5 16726 { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16727 { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16728 { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16729 { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 },
philpem@5 16730 { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16731 { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16732 { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16733 { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
philpem@5 16734 { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }};
philpem@5 16735
philpem@5 16736 const unsigned int
philpem@5 16737 nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1,
philpem@5 16738 ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1,
philpem@5 16739 nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1;
philpem@5 16740 if (!nxm1 || !nym1 || !nzm1) return CImg<floatT>();
philpem@5 16741
philpem@5 16742 primitives.assign();
philpem@5 16743 CImgList<floatT> points;
philpem@5 16744 CImg<intT> indices1(nx,ny,1,3,-1), indices2(indices1);
philpem@5 16745 CImg<floatT> values1(nx,ny), values2(nx,ny);
philpem@5 16746 float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0;
philpem@5 16747
philpem@5 16748 // Fill the first plane with function values
philpem@5 16749 Y = y0;
philpem@5 16750 cimg_forY(values1,y) {
philpem@5 16751 X = x0;
philpem@5 16752 cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; }
philpem@5 16753 Y+=resy;
philpem@5 16754 }
philpem@5 16755
philpem@5 16756 // Run Marching Cubes algorithm
philpem@5 16757 Z = z0; nZ = Z + resz;
philpem@5 16758 for (unsigned int zi = 0; zi<nzm1; ++zi, Z = nZ, nZ+=resz) {
philpem@5 16759 Y = y0; nY = Y + resy;
philpem@5 16760 indices2.fill(-1);
philpem@5 16761 for (unsigned int yi = 0, nyi = 1; yi<nym1; ++yi, ++nyi, Y = nY, nY+=resy) {
philpem@5 16762 X = x0; nX = X + resx;
philpem@5 16763 for (unsigned int xi = 0, nxi = 1; xi<nxm1; ++xi, ++nxi, X = nX, nX+=resx) {
philpem@5 16764
philpem@5 16765 // Determine cube configuration
philpem@5 16766 const float
philpem@5 16767 val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi),
philpem@5 16768 val4 = values2(xi,yi) = (float)func(X,Y,nZ),
philpem@5 16769 val5 = values2(nxi,yi) = (float)func(nX,Y,nZ),
philpem@5 16770 val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ),
philpem@5 16771 val7 = values2(xi,nyi) = (float)func(X,nY,nZ);
philpem@5 16772
philpem@5 16773 const unsigned int configuration =
philpem@5 16774 (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0) |
philpem@5 16775 (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0),
philpem@5 16776 edge = edges[configuration];
philpem@5 16777
philpem@5 16778 // Compute intersection points
philpem@5 16779 if (edge) {
philpem@5 16780 if ((edge&1) && indices1(xi,yi,0)<0) {
philpem@5 16781 const float Xi = X + (isovalue-val0)*resx/(val1-val0);
philpem@5 16782 indices1(xi,yi,0) = points.size;
philpem@5 16783 points.insert(CImg<floatT>::vector(Xi,Y,Z));
philpem@5 16784 }
philpem@5 16785 if ((edge&2) && indices1(nxi,yi,1)<0) {
philpem@5 16786 const float Yi = Y + (isovalue-val1)*resy/(val2-val1);
philpem@5 16787 indices1(nxi,yi,1) = points.size;
philpem@5 16788 points.insert(CImg<floatT>::vector(nX,Yi,Z));
philpem@5 16789 }
philpem@5 16790 if ((edge&4) && indices1(xi,nyi,0)<0) {
philpem@5 16791 const float Xi = X + (isovalue-val3)*resx/(val2-val3);
philpem@5 16792 indices1(xi,nyi,0) = points.size;
philpem@5 16793 points.insert(CImg<floatT>::vector(Xi,nY,Z));
philpem@5 16794 }
philpem@5 16795 if ((edge&8) && indices1(xi,yi,1)<0) {
philpem@5 16796 const float Yi = Y + (isovalue-val0)*resy/(val3-val0);
philpem@5 16797 indices1(xi,yi,1) = points.size;
philpem@5 16798 points.insert(CImg<floatT>::vector(X,Yi,Z));
philpem@5 16799 }
philpem@5 16800 if ((edge&16) && indices2(xi,yi,0)<0) {
philpem@5 16801 const float Xi = X + (isovalue-val4)*resx/(val5-val4);
philpem@5 16802 indices2(xi,yi,0) = points.size;
philpem@5 16803 points.insert(CImg<floatT>::vector(Xi,Y,nZ));
philpem@5 16804 }
philpem@5 16805 if ((edge&32) && indices2(nxi,yi,1)<0) {
philpem@5 16806 const float Yi = Y + (isovalue-val5)*resy/(val6-val5);
philpem@5 16807 indices2(nxi,yi,1) = points.size;
philpem@5 16808 points.insert(CImg<floatT>::vector(nX,Yi,nZ));
philpem@5 16809 }
philpem@5 16810 if ((edge&64) && indices2(xi,nyi,0)<0) {
philpem@5 16811 const float Xi = X + (isovalue-val7)*resx/(val6-val7);
philpem@5 16812 indices2(xi,nyi,0) = points.size;
philpem@5 16813 points.insert(CImg<floatT>::vector(Xi,nY,nZ));
philpem@5 16814 }
philpem@5 16815 if ((edge&128) && indices2(xi,yi,1)<0) {
philpem@5 16816 const float Yi = Y + (isovalue-val4)*resy/(val7-val4);
philpem@5 16817 indices2(xi,yi,1) = points.size;
philpem@5 16818 points.insert(CImg<floatT>::vector(X,Yi,nZ));
philpem@5 16819 }
philpem@5 16820 if ((edge&256) && indices1(xi,yi,2)<0) {
philpem@5 16821 const float Zi = Z+ (isovalue-val0)*resz/(val4-val0);
philpem@5 16822 indices1(xi,yi,2) = points.size;
philpem@5 16823 points.insert(CImg<floatT>::vector(X,Y,Zi));
philpem@5 16824 }
philpem@5 16825 if ((edge&512) && indices1(nxi,yi,2)<0) {
philpem@5 16826 const float Zi = Z + (isovalue-val1)*resz/(val5-val1);
philpem@5 16827 indices1(nxi,yi,2) = points.size;
philpem@5 16828 points.insert(CImg<floatT>::vector(nX,Y,Zi));
philpem@5 16829 }
philpem@5 16830 if ((edge&1024) && indices1(nxi,nyi,2)<0) {
philpem@5 16831 const float Zi = Z + (isovalue-val2)*resz/(val6-val2);
philpem@5 16832 indices1(nxi,nyi,2) = points.size;
philpem@5 16833 points.insert(CImg<floatT>::vector(nX,nY,Zi));
philpem@5 16834 }
philpem@5 16835 if ((edge&2048) && indices1(xi,nyi,2)<0) {
philpem@5 16836 const float Zi = Z + (isovalue-val3)*resz/(val7-val3);
philpem@5 16837 indices1(xi,nyi,2) = points.size;
philpem@5 16838 points.insert(CImg<floatT>::vector(X,nY,Zi));
philpem@5 16839 }
philpem@5 16840
philpem@5 16841 // Create triangles
philpem@5 16842 for (int *triangle = triangles[configuration]; *triangle!=-1; ) {
philpem@5 16843 const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++);
philpem@5 16844 const tf
philpem@5 16845 i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)),
philpem@5 16846 i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)),
philpem@5 16847 i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi));
philpem@5 16848 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
philpem@5 16849 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
philpem@5 16850 }
philpem@5 16851 }
philpem@5 16852 }
philpem@5 16853 }
philpem@5 16854 cimg::swap(values1,values2);
philpem@5 16855 cimg::swap(indices1,indices2);
philpem@5 16856 }
philpem@5 16857 return points.get_append('x');
philpem@5 16858 }
philpem@5 16859
philpem@5 16860 struct _marching_squares_func {
philpem@5 16861 const CImg<T>& ref;
philpem@5 16862 _marching_squares_func(const CImg<T>& pref):ref(pref) {}
philpem@5 16863 float operator()(const float x, const float y) const {
philpem@5 16864 return (float)ref((int)x,(int)y);
philpem@5 16865 }
philpem@5 16866 };
philpem@5 16867
philpem@5 16868 struct _marching_cubes_func {
philpem@5 16869 const CImg<T>& ref;
philpem@5 16870 _marching_cubes_func(const CImg<T>& pref):ref(pref) {}
philpem@5 16871 float operator()(const float x, const float y, const float z) const {
philpem@5 16872 return (float)ref((int)x,(int)y,(int)z);
philpem@5 16873 }
philpem@5 16874 };
philpem@5 16875
philpem@5 16876 struct _marching_squares_func_float {
philpem@5 16877 const CImg<T>& ref;
philpem@5 16878 _marching_squares_func_float(const CImg<T>& pref):ref(pref) {}
philpem@5 16879 float operator()(const float x, const float y) const {
philpem@5 16880 return (float)ref._linear_atXY(x,y);
philpem@5 16881 }
philpem@5 16882 };
philpem@5 16883
philpem@5 16884 struct _marching_cubes_func_float {
philpem@5 16885 const CImg<T>& ref;
philpem@5 16886 _marching_cubes_func_float(const CImg<T>& pref):ref(pref) {}
philpem@5 16887 float operator()(const float x, const float y, const float z) const {
philpem@5 16888 return (float)ref._linear_atXYZ(x,y,z);
philpem@5 16889 }
philpem@5 16890 };
philpem@5 16891
philpem@5 16892 //! Compute a vectorization of an implicit function.
philpem@5 16893 template<typename tf>
philpem@5 16894 CImg<floatT> get_isovalue3d(CImgList<tf>& primitives, const float isovalue,
philpem@5 16895 const float resx=1, const float resy=1, const float resz=1,
philpem@5 16896 const bool invert_faces=false) const {
philpem@5 16897 primitives.assign();
philpem@5 16898 if (is_empty()) return *this;
philpem@5 16899 if (dim>1)
philpem@5 16900 throw CImgInstanceException("CImg<%s>::get_isovalue3d() : Instance image (%u,%u,%u,%u,%p) is not a scalar image.",
philpem@5 16901 pixel_type(),width,height,depth,dim,data);
philpem@5 16902 CImg<floatT> points;
philpem@5 16903 if (depth>1) {
philpem@5 16904 if (resx==1 && resy==1 && resz==1) {
philpem@5 16905 const _marching_cubes_func func(*this);
philpem@5 16906 points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
philpem@5 16907 } else {
philpem@5 16908 const _marching_cubes_func_float func(*this);
philpem@5 16909 points = marching_cubes(primitives,func,isovalue,0,0,0,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f,resx,resy,resz,invert_faces);
philpem@5 16910 }
philpem@5 16911 } else {
philpem@5 16912 if (resx==1 && resy==1) {
philpem@5 16913 const _marching_squares_func func(*this);
philpem@5 16914 points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
philpem@5 16915 } else {
philpem@5 16916 const _marching_squares_func_float func(*this);
philpem@5 16917 points = marching_squares(primitives,func,isovalue,0,0,dimx()-1.0f,dimy()-1.0f,resx,resy);
philpem@5 16918 }
philpem@5 16919 if (points) points.resize(-100,3,1,1,0);
philpem@5 16920 }
philpem@5 16921 return points;
philpem@5 16922 }
philpem@5 16923
philpem@5 16924 //! Translate a 3D object.
philpem@5 16925 CImg<T>& translate_object3d(const float tx, const float ty=0, const float tz=0) {
philpem@5 16926 get_shared_line(0)+=tx; get_shared_line(1)+=ty; get_shared_line(2)+=tz;
philpem@5 16927 return *this;
philpem@5 16928 }
philpem@5 16929
philpem@5 16930 CImg<Tfloat> get_translate_object3d(const float tx, const float ty=0, const float tz=0) const {
philpem@5 16931 return CImg<Tfloat>(*this,false).translate_object3d(tx,ty,tz);
philpem@5 16932 }
philpem@5 16933
philpem@5 16934 //! Translate a 3D object so that it becomes centered.
philpem@5 16935 CImg<T>& translate_object3d() {
philpem@5 16936 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
philpem@5 16937 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
philpem@5 16938 xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2;
philpem@5 16939 return *this;
philpem@5 16940 }
philpem@5 16941
philpem@5 16942 CImg<Tfloat> get_translate_object3d() const {
philpem@5 16943 return CImg<Tfloat>(*this,false).translate_object3d();
philpem@5 16944 }
philpem@5 16945
philpem@5 16946 //! Resize a 3D object.
philpem@5 16947 CImg<T>& resize_object3d(const float sx, const float sy=-100, const float sz=-100) {
philpem@5 16948 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
philpem@5 16949 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
philpem@5 16950 if (xm<xM) { if (sx>0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; }
philpem@5 16951 if (ym<yM) { if (sy>0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; }
philpem@5 16952 if (zm<zM) { if (sz>0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; }
philpem@5 16953 return *this;
philpem@5 16954 }
philpem@5 16955
philpem@5 16956 CImg<Tfloat> get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const {
philpem@5 16957 return CImg<Tfloat>(*this,false).resize_object3d(sx,sy,sz);
philpem@5 16958 }
philpem@5 16959
philpem@5 16960 // Resize a 3D object so that its max dimension if one.
philpem@5 16961 CImg<T> resize_object3d() const {
philpem@5 16962 CImg<T> xcoords = get_shared_line(0), ycoords = get_shared_line(1), zcoords = get_shared_line(2);
philpem@5 16963 float xm, xM = (float)xcoords.maxmin(xm), ym, yM = (float)ycoords.maxmin(ym), zm, zM = (float)zcoords.maxmin(zm);
philpem@5 16964 const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz);
philpem@5 16965 if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; }
philpem@5 16966 return *this;
philpem@5 16967 }
philpem@5 16968
philpem@5 16969 CImg<Tfloat> get_resize_object3d() const {
philpem@5 16970 return CImg<Tfloat>(*this,false).resize_object3d();
philpem@5 16971 }
philpem@5 16972
philpem@5 16973 //! Append a 3D object to another one.
philpem@5 16974 template<typename tf, typename tp, typename tff>
philpem@5 16975 CImg<T>& append_object3d(CImgList<tf>& primitives, const CImg<tp>& obj_points, const CImgList<tff>& obj_primitives) {
philpem@5 16976 const unsigned int P = width;
philpem@5 16977 append(obj_points,'x');
philpem@5 16978 const unsigned int N = primitives.size;
philpem@5 16979 primitives.insert(obj_primitives);
philpem@5 16980 for (unsigned int i = N; i<primitives.size; ++i) {
philpem@5 16981 CImg<tf> &p = primitives[i];
philpem@5 16982 if (p.size()!=5) p+=P;
philpem@5 16983 else { p[0]+=P; if (p[2]==0) p[1]+=P; }
philpem@5 16984 }
philpem@5 16985 return *this;
philpem@5 16986 }
philpem@5 16987
philpem@5 16988 //@}
philpem@5 16989 //----------------------------
philpem@5 16990 //
philpem@5 16991 //! \name Color bases
philpem@5 16992 //@{
philpem@5 16993 //----------------------------
philpem@5 16994
philpem@5 16995 //! Return a default indexed color palette with 256 (R,G,B) entries.
philpem@5 16996 /**
philpem@5 16997 The default color palette is used by %CImg when displaying images on 256 colors displays.
philpem@5 16998 It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding
philpem@5 16999 (i.e 8 levels for the Red and Green and 4 levels for the Blue).
philpem@5 17000 \return a 1x256x1x3 color image defining the palette entries.
philpem@5 17001 **/
philpem@5 17002 static CImg<Tuchar> default_LUT8() {
philpem@5 17003 static CImg<Tuchar> palette;
philpem@5 17004 if (!palette) {
philpem@5 17005 palette.assign(1,256,1,3);
philpem@5 17006 for (unsigned int index = 0, r = 16; r<256; r+=32)
philpem@5 17007 for (unsigned int g = 16; g<256; g+=32)
philpem@5 17008 for (unsigned int b = 32; b<256; b+=64) {
philpem@5 17009 palette(0,index,0) = (Tuchar)r;
philpem@5 17010 palette(0,index,1) = (Tuchar)g;
philpem@5 17011 palette(0,index++,2) = (Tuchar)b;
philpem@5 17012 }
philpem@5 17013 }
philpem@5 17014 return palette;
philpem@5 17015 }
philpem@5 17016
philpem@5 17017 //! Return a rainbow color palette with 256 (R,G,B) entries.
philpem@5 17018 static CImg<Tuchar> rainbow_LUT8() {
philpem@5 17019 static CImg<Tuchar> palette;
philpem@5 17020 if (!palette) {
philpem@5 17021 CImg<Tint> tmp(1,256,1,3,1);
philpem@5 17022 tmp.get_shared_channel(0).sequence(0,359);
philpem@5 17023 palette = tmp.HSVtoRGB();
philpem@5 17024 }
philpem@5 17025 return palette;
philpem@5 17026 }
philpem@5 17027
philpem@5 17028 //! Return a contrasted color palette with 256 (R,G,B) entries.
philpem@5 17029 static CImg<Tuchar> contrast_LUT8() {
philpem@5 17030 static const unsigned char pal[] = {
philpem@5 17031 217,62,88,75,1,237,240,12,56,160,165,116,1,1,204,2,15,248,148,185,133,141,46,246,222,116,16,5,207,226,
philpem@5 17032 17,114,247,1,214,53,238,0,95,55,233,235,109,0,17,54,33,0,90,30,3,0,94,27,19,0,68,212,166,130,0,15,7,119,
philpem@5 17033 238,2,246,198,0,3,16,10,13,2,25,28,12,6,2,99,18,141,30,4,3,140,12,4,30,233,7,10,0,136,35,160,168,184,20,
philpem@5 17034 233,0,1,242,83,90,56,180,44,41,0,6,19,207,5,31,214,4,35,153,180,75,21,76,16,202,218,22,17,2,136,71,74,
philpem@5 17035 81,251,244,148,222,17,0,234,24,0,200,16,239,15,225,102,230,186,58,230,110,12,0,7,129,249,22,241,37,219,
philpem@5 17036 1,3,254,210,3,212,113,131,197,162,123,252,90,96,209,60,0,17,0,180,249,12,112,165,43,27,229,77,40,195,12,
philpem@5 17037 87,1,210,148,47,80,5,9,1,137,2,40,57,205,244,40,8,252,98,0,40,43,206,31,187,0,180,1,69,70,227,131,108,0,
philpem@5 17038 223,94,228,35,248,243,4,16,0,34,24,2,9,35,73,91,12,199,51,1,249,12,103,131,20,224,2,70,32,
philpem@5 17039 233,1,165,3,8,154,246,233,196,5,0,6,183,227,247,195,208,36,0,0,226,160,210,198,69,153,210,1,23,8,192,2,4,
philpem@5 17040 137,1,0,52,2,249,241,129,0,0,234,7,238,71,7,32,15,157,157,252,158,2,250,6,13,30,11,162,0,199,21,11,27,224,
philpem@5 17041 4,157,20,181,111,187,218,3,0,11,158,230,196,34,223,22,248,135,254,210,157,219,0,117,239,3,255,4,227,5,247,
philpem@5 17042 11,4,3,188,111,11,105,195,2,0,14,1,21,219,192,0,183,191,113,241,1,12,17,248,0,48,7,19,1,254,212,0,239,246,
philpem@5 17043 0,23,0,250,165,194,194,17,3,253,0,24,6,0,141,167,221,24,212,2,235,243,0,0,205,1,251,133,204,28,4,6,1,10,
philpem@5 17044 141,21,74,12,236,254,228,19,1,0,214,1,186,13,13,6,13,16,27,209,6,216,11,207,251,59,32,9,155,23,19,235,143,
philpem@5 17045 116,6,213,6,75,159,23,6,0,228,4,10,245,249,1,7,44,234,4,102,174,0,19,239,103,16,15,18,8,214,22,4,47,244,
philpem@5 17046 255,8,0,251,173,1,212,252,250,251,252,6,0,29,29,222,233,246,5,149,0,182,180,13,151,0,203,183,0,35,149,0,
philpem@5 17047 235,246,254,78,9,17,203,73,11,195,0,3,5,44,0,0,237,5,106,6,130,16,214,20,168,247,168,4,207,11,5,1,232,251,
philpem@5 17048 129,210,116,231,217,223,214,27,45,38,4,177,186,249,7,215,172,16,214,27,249,230,236,2,34,216,217,0,175,30,
philpem@5 17049 243,225,244,182,20,212,2,226,21,255,20,0,2,13,62,13,191,14,76,64,20,121,4,118,0,216,1,147,0,2,210,1,215,
philpem@5 17050 95,210,236,225,184,46,0,248,24,11,1,9,141,250,243,9,221,233,160,11,147,2,55,8,23,12,253,9,0,54,0,231,6,3,
philpem@5 17051 141,8,2,246,9,180,5,11,8,227,8,43,110,242,1,130,5,97,36,10,6,219,86,133,11,108,6,1,5,244,67,19,28,0,174,
philpem@5 17052 154,16,127,149,252,188,196,196,228,244,9,249,0,0,0,37,170,32,250,0,73,255,23,3,224,234,38,195,198,0,255,87,
philpem@5 17053 33,221,174,31,3,0,189,228,6,153,14,144,14,108,197,0,9,206,245,254,3,16,253,178,248,0,95,125,8,0,3,168,21,
philpem@5 17054 23,168,19,50,240,244,185,0,1,144,10,168,31,82,1,13 };
philpem@5 17055 static const CImg<Tuchar> palette(pal,1,256,1,3,false);
philpem@5 17056 return palette;
philpem@5 17057 }
philpem@5 17058
philpem@5 17059 //! Convert (R,G,B) color image to indexed color image.
philpem@5 17060 template<typename t>
philpem@5 17061 CImg<T>& RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) {
philpem@5 17062 return get_RGBtoLUT(palette,dithering,indexing).transfer_to(*this);
philpem@5 17063 }
philpem@5 17064
philpem@5 17065 template<typename t>
philpem@5 17066 CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true, const bool indexing=false) const {
philpem@5 17067 if (is_empty()) return CImg<t>();
philpem@5 17068 if (dim!=3)
philpem@5 17069 throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, "
philpem@5 17070 "should be a (R,G,B) image.",
philpem@5 17071 pixel_type(),dim);
philpem@5 17072 if (palette.data && palette.dim!=3)
philpem@5 17073 throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, "
philpem@5 17074 "should be a (R,G,B) palette",
philpem@5 17075 pixel_type(),palette.dim);
philpem@5 17076 CImg<t> res(width,height,depth,indexing?1:3);
philpem@5 17077 float *line1 = new float[3*width], *line2 = new float[3*width];
philpem@5 17078 t *pRd = res.ptr(0,0,0,0), *pGd = indexing?pRd:res.ptr(0,0,0,1), *pBd = indexing?pRd:res.ptr(0,0,0,2);
philpem@5 17079 cimg_forZ(*this,z) {
philpem@5 17080 const T *pRs = ptr(0,0,z,0), *pGs = ptr(0,0,z,1), *pBs = ptr(0,0,z,2);
philpem@5 17081 float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
philpem@5 17082 cimg_forY(*this,y) {
philpem@5 17083 cimg::swap(line1,line2);
philpem@5 17084 if (y<dimy()-1) {
philpem@5 17085 const int ny = y + 1;
philpem@5 17086 const T *pRs = ptr(0,ny,z,0), *pGs = ptr(0,ny,z,1), *pBs = ptr(0,ny,z,2);
philpem@5 17087 float *ptrd = line2; cimg_forX(*this,x) { *(ptrd++) = (float)*(pRs++); *(ptrd++) = (float)*(pGs++); *(ptrd++) = (float)*(pBs++); }
philpem@5 17088 }
philpem@5 17089 float *ptr1 = line1, *ptr2 = line2;
philpem@5 17090 cimg_forX(*this,x) {
philpem@5 17091 float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++);
philpem@5 17092 R = R<0?0:(R>255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B);
philpem@5 17093 t Rbest = 0, Gbest = 0, Bbest = 0;
philpem@5 17094 int best_index = 0;
philpem@5 17095 if (palette) { // find best match in given color palette
philpem@5 17096 const t *pRs = palette.ptr(0,0,0,0), *pGs = palette.ptr(0,0,0,1), *pBs = palette.ptr(0,0,0,2);
philpem@5 17097 const unsigned int Npal = palette.width*palette.height*palette.depth;
philpem@5 17098 float min = cimg::type<float>::max();
philpem@5 17099 for (unsigned int off = 0; off<Npal; ++off) {
philpem@5 17100 const t Rp = *(pRs++), Gp = *(pGs++), Bp = *(pBs++);
philpem@5 17101 const float error = cimg::sqr((float)Rp-(float)R) + cimg::sqr((float)Gp-(float)G) + cimg::sqr((float)Bp-(float)B);
philpem@5 17102 if (error<min) { min = error; best_index = off; Rbest = Rp; Gbest = Gp; Bbest = Bp; }
philpem@5 17103 }
philpem@5 17104 } else {
philpem@5 17105 Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0);
philpem@5 17106 best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>3) | ((unsigned char)Bbest>>6);
philpem@5 17107 }
philpem@5 17108 if (indexing) *(pRd++) = (t)best_index; else { *(pRd++) = Rbest; *(pGd++) = Gbest; *(pBd++) = Bbest; }
philpem@5 17109 if (dithering) { // apply dithering to neighborhood pixels if needed
philpem@5 17110 const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest);
philpem@5 17111 if (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; }
philpem@5 17112 if (y<dimy()-1) {
philpem@5 17113 *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2;
philpem@5 17114 if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; }
philpem@5 17115 if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; }
philpem@5 17116 }
philpem@5 17117 }
philpem@5 17118 ptr2+=3;
philpem@5 17119 }
philpem@5 17120 }
philpem@5 17121 }
philpem@5 17122 delete[] line1; delete[] line2;
philpem@5 17123 return res;
philpem@5 17124 }
philpem@5 17125
philpem@5 17126 //! Convert color pixels from (R,G,B) to match the default palette.
philpem@5 17127 CImg<T>& RGBtoLUT(const bool dithering=true, const bool indexing=false) {
philpem@5 17128 return get_RGBtoLUT(dithering,indexing).transfer_to(*this);
philpem@5 17129 }
philpem@5 17130
philpem@5 17131 CImg<Tuchar> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const {
philpem@5 17132 static const CImg<Tuchar> empty;
philpem@5 17133 return get_RGBtoLUT(empty,dithering,indexing);
philpem@5 17134 }
philpem@5 17135
philpem@5 17136 //! Convert an indexed image to a (R,G,B) image using the specified color palette.
philpem@5 17137 CImg<T>& LUTtoRGB(const CImg<T>& palette) {
philpem@5 17138 return get_LUTtoRGB(palette).transfer_to(*this);
philpem@5 17139 }
philpem@5 17140
philpem@5 17141 template<typename t>
philpem@5 17142 CImg<t> get_LUTtoRGB(const CImg<t>& palette) const {
philpem@5 17143 if (is_empty()) return CImg<t>();
philpem@5 17144 if (dim!=1)
philpem@5 17145 throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, "
philpem@5 17146 "should be a LUT image",
philpem@5 17147 pixel_type(),dim);
philpem@5 17148 if (palette.data && palette.dim!=3)
philpem@5 17149 throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, "
philpem@5 17150 "should be a (R,G,B) palette",
philpem@5 17151 pixel_type(),palette.dim);
philpem@5 17152 const CImg<t> pal = palette.data?palette:CImg<t>(default_LUT8());
philpem@5 17153 CImg<t> res(width,height,depth,3);
philpem@5 17154 const t *pRs = pal.ptr(0,0,0,0), *pGs = pal.ptr(0,0,0,1), *pBs = pal.ptr(0,0,0,2);
philpem@5 17155 t *pRd = res.ptr(0,0,0,1), *pGd = pRd + width*height*depth, *pBd = pGd + width*height*depth;
philpem@5 17156 const unsigned int Npal = palette.width*palette.height*palette.depth;
philpem@5 17157 cimg_for(*this,ptr,T) {
philpem@5 17158 const unsigned int index = ((unsigned int)*ptr)%Npal;
philpem@5 17159 *(--pRd) = pRs[index]; *(--pGd) = pGs[index]; *(--pBd) = pBs[index];
philpem@5 17160 }
philpem@5 17161 return res;
philpem@5 17162 }
philpem@5 17163
philpem@5 17164 //! Convert an indexed image (with the default palette) to a (R,G,B) image.
philpem@5 17165 CImg<T>& LUTtoRGB() {
philpem@5 17166 return get_LUTtoRGB().transfer_to(*this);
philpem@5 17167 }
philpem@5 17168
philpem@5 17169 CImg<Tuchar> get_LUTtoRGB() const {
philpem@5 17170 static const CImg<Tuchar> empty;
philpem@5 17171 return get_LUTtoRGB(empty);
philpem@5 17172 }
philpem@5 17173
philpem@5 17174 //! Convert color pixels from (R,G,B) to (H,S,V).
philpem@5 17175 CImg<T>& RGBtoHSV() {
philpem@5 17176 if (is_empty()) return *this;
philpem@5 17177 if (dim!=3)
philpem@5 17178 throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, "
philpem@5 17179 "should be a (R,G,B) image.",
philpem@5 17180 pixel_type(),dim);
philpem@5 17181 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17182 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17183 const Tfloat
philpem@5 17184 R = (Tfloat)*p1,
philpem@5 17185 G = (Tfloat)*p2,
philpem@5 17186 B = (Tfloat)*p3,
philpem@5 17187 nR = (R<0?0:(R>255?255:R))/255,
philpem@5 17188 nG = (G<0?0:(G>255?255:G))/255,
philpem@5 17189 nB = (B<0?0:(B>255?255:B))/255,
philpem@5 17190 m = cimg::min(nR,nG,nB),
philpem@5 17191 M = cimg::max(nR,nG,nB);
philpem@5 17192 Tfloat H = 0, S = 0;
philpem@5 17193 if (M!=m) {
philpem@5 17194 const Tfloat
philpem@5 17195 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
philpem@5 17196 i = (Tfloat)((nR==m)?3:((nG==m)?5:1));
philpem@5 17197 H = (i-f/(M-m));
philpem@5 17198 if (H>=6) H-=6;
philpem@5 17199 H*=60;
philpem@5 17200 S = (M-m)/M;
philpem@5 17201 }
philpem@5 17202 *(p1++) = (T)H;
philpem@5 17203 *(p2++) = (T)S;
philpem@5 17204 *(p3++) = (T)M;
philpem@5 17205 }
philpem@5 17206 return *this;
philpem@5 17207 }
philpem@5 17208
philpem@5 17209 CImg<Tfloat> get_RGBtoHSV() const {
philpem@5 17210 return CImg<Tfloat>(*this,false).RGBtoHSV();
philpem@5 17211 }
philpem@5 17212
philpem@5 17213 //! Convert color pixels from (H,S,V) to (R,G,B).
philpem@5 17214 CImg<T>& HSVtoRGB() {
philpem@5 17215 if (is_empty()) return *this;
philpem@5 17216 if (dim!=3)
philpem@5 17217 throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, "
philpem@5 17218 "should be a (H,S,V) image",
philpem@5 17219 pixel_type(),dim);
philpem@5 17220 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17221 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17222 Tfloat
philpem@5 17223 H = (Tfloat)*p1,
philpem@5 17224 S = (Tfloat)*p2,
philpem@5 17225 V = (Tfloat)*p3,
philpem@5 17226 R = 0, G = 0, B = 0;
philpem@5 17227 if (H==0 && S==0) R = G = B = V;
philpem@5 17228 else {
philpem@5 17229 H/=60;
philpem@5 17230 const int i = (int)cimg_std::floor(H);
philpem@5 17231 const Tfloat
philpem@5 17232 f = (i&1)?(H-i):(1-H+i),
philpem@5 17233 m = V*(1-S),
philpem@5 17234 n = V*(1-S*f);
philpem@5 17235 switch (i) {
philpem@5 17236 case 6 :
philpem@5 17237 case 0 : R = V; G = n; B = m; break;
philpem@5 17238 case 1 : R = n; G = V; B = m; break;
philpem@5 17239 case 2 : R = m; G = V; B = n; break;
philpem@5 17240 case 3 : R = m; G = n; B = V; break;
philpem@5 17241 case 4 : R = n; G = m; B = V; break;
philpem@5 17242 case 5 : R = V; G = m; B = n; break;
philpem@5 17243 }
philpem@5 17244 }
philpem@5 17245 R*=255; G*=255; B*=255;
philpem@5 17246 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17247 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17248 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17249 }
philpem@5 17250 return *this;
philpem@5 17251 }
philpem@5 17252
philpem@5 17253 CImg<Tuchar> get_HSVtoRGB() const {
philpem@5 17254 return CImg<Tuchar>(*this,false).HSVtoRGB();
philpem@5 17255 }
philpem@5 17256
philpem@5 17257 //! Convert color pixels from (R,G,B) to (H,S,L).
philpem@5 17258 CImg<T>& RGBtoHSL() {
philpem@5 17259 if (is_empty()) return *this;
philpem@5 17260 if (dim!=3)
philpem@5 17261 throw CImgInstanceException("CImg<%s>::RGBtoHSL() : Input image dimension is dim=%u, "
philpem@5 17262 "should be a (R,G,B) image.",
philpem@5 17263 pixel_type(),dim);
philpem@5 17264 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17265 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17266 const Tfloat
philpem@5 17267 R = (Tfloat)*p1,
philpem@5 17268 G = (Tfloat)*p2,
philpem@5 17269 B = (Tfloat)*p3,
philpem@5 17270 nR = (R<0?0:(R>255?255:R))/255,
philpem@5 17271 nG = (G<0?0:(G>255?255:G))/255,
philpem@5 17272 nB = (B<0?0:(B>255?255:B))/255,
philpem@5 17273 m = cimg::min(nR,nG,nB),
philpem@5 17274 M = cimg::max(nR,nG,nB),
philpem@5 17275 L = (m+M)/2;
philpem@5 17276 Tfloat H = 0, S = 0;
philpem@5 17277 if (M==m) H = S = 0;
philpem@5 17278 else {
philpem@5 17279 const Tfloat
philpem@5 17280 f = (nR==m)?(nG-nB):((nG==m)?(nB-nR):(nR-nG)),
philpem@5 17281 i = (nR==m)?3.0f:((nG==m)?5.0f:1.0f);
philpem@5 17282 H = (i-f/(M-m));
philpem@5 17283 if (H>=6) H-=6;
philpem@5 17284 H*=60;
philpem@5 17285 S = (2*L<=1)?((M-m)/(M+m)):((M-m)/(2-M-m));
philpem@5 17286 }
philpem@5 17287 *(p1++) = (T)H;
philpem@5 17288 *(p2++) = (T)S;
philpem@5 17289 *(p3++) = (T)L;
philpem@5 17290 }
philpem@5 17291 return *this;
philpem@5 17292 }
philpem@5 17293
philpem@5 17294 CImg<Tfloat> get_RGBtoHSL() const {
philpem@5 17295 return CImg< Tfloat>(*this,false).RGBtoHSL();
philpem@5 17296 }
philpem@5 17297
philpem@5 17298 //! Convert color pixels from (H,S,L) to (R,G,B).
philpem@5 17299 CImg<T>& HSLtoRGB() {
philpem@5 17300 if (is_empty()) return *this;
philpem@5 17301 if (dim!=3)
philpem@5 17302 throw CImgInstanceException("CImg<%s>::HSLtoRGB() : Input image dimension is dim=%u, "
philpem@5 17303 "should be a (H,S,V) image",
philpem@5 17304 pixel_type(),dim);
philpem@5 17305 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17306 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17307 const Tfloat
philpem@5 17308 H = (Tfloat)*p1,
philpem@5 17309 S = (Tfloat)*p2,
philpem@5 17310 L = (Tfloat)*p3,
philpem@5 17311 q = 2*L<1?L*(1+S):(L+S-L*S),
philpem@5 17312 p = 2*L-q,
philpem@5 17313 h = H/360,
philpem@5 17314 tr = h + 1.0f/3,
philpem@5 17315 tg = h,
philpem@5 17316 tb = h - 1.0f/3,
philpem@5 17317 ntr = tr<0?tr+1:(tr>1?tr-1:tr),
philpem@5 17318 ntg = tg<0?tg+1:(tg>1?tg-1:tg),
philpem@5 17319 ntb = tb<0?tb+1:(tb>1?tb-1:tb),
philpem@5 17320 R = 255*(6*ntr<1?p+(q-p)*6*ntr:(2*ntr<1?q:(3*ntr<2?p+(q-p)*6*(2.0f/3-ntr):p))),
philpem@5 17321 G = 255*(6*ntg<1?p+(q-p)*6*ntg:(2*ntg<1?q:(3*ntg<2?p+(q-p)*6*(2.0f/3-ntg):p))),
philpem@5 17322 B = 255*(6*ntb<1?p+(q-p)*6*ntb:(2*ntb<1?q:(3*ntb<2?p+(q-p)*6*(2.0f/3-ntb):p)));
philpem@5 17323 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17324 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17325 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17326 }
philpem@5 17327 return *this;
philpem@5 17328 }
philpem@5 17329
philpem@5 17330 CImg<Tuchar> get_HSLtoRGB() const {
philpem@5 17331 return CImg<Tuchar>(*this,false).HSLtoRGB();
philpem@5 17332 }
philpem@5 17333
philpem@5 17334 //! Convert color pixels from (R,G,B) to (H,S,I).
philpem@5 17335 //! Reference: "Digital Image Processing, 2nd. edition", R. Gonzalez and R. Woods. Prentice Hall, 2002.
philpem@5 17336 CImg<T>& RGBtoHSI() {
philpem@5 17337 if (is_empty()) return *this;
philpem@5 17338 if (dim!=3)
philpem@5 17339 throw CImgInstanceException("CImg<%s>::RGBtoHSI() : Input image dimension is dim=%u, "
philpem@5 17340 "should be a (R,G,B) image.",
philpem@5 17341 pixel_type(),dim);
philpem@5 17342 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17343 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17344 const Tfloat
philpem@5 17345 R = (Tfloat)*p1,
philpem@5 17346 G = (Tfloat)*p2,
philpem@5 17347 B = (Tfloat)*p3,
philpem@5 17348 nR = (R<0?0:(R>255?255:R))/255,
philpem@5 17349 nG = (G<0?0:(G>255?255:G))/255,
philpem@5 17350 nB = (B<0?0:(B>255?255:B))/255,
philpem@5 17351 m = cimg::min(nR,nG,nB),
philpem@5 17352 theta = (Tfloat)(cimg_std::acos(0.5f*((nR-nG)+(nR-nB))/cimg_std::sqrt(cimg_std::pow(nR-nG,2)+(nR-nB)*(nG-nB)))*180/cimg::valuePI),
philpem@5 17353 sum = nR + nG + nB;
philpem@5 17354 Tfloat H = 0, S = 0, I = 0;
philpem@5 17355 if (theta>0) H = (nB<=nG)?theta:360-theta;
philpem@5 17356 if (sum>0) S = 1 - 3/sum*m;
philpem@5 17357 I = sum/3;
philpem@5 17358 *(p1++) = (T)H;
philpem@5 17359 *(p2++) = (T)S;
philpem@5 17360 *(p3++) = (T)I;
philpem@5 17361 }
philpem@5 17362 return *this;
philpem@5 17363 }
philpem@5 17364
philpem@5 17365 CImg<Tfloat> get_RGBtoHSI() const {
philpem@5 17366 return CImg<Tfloat>(*this,false).RGBtoHSI();
philpem@5 17367 }
philpem@5 17368
philpem@5 17369 //! Convert color pixels from (H,S,I) to (R,G,B).
philpem@5 17370 CImg<T>& HSItoRGB() {
philpem@5 17371 if (is_empty()) return *this;
philpem@5 17372 if (dim!=3)
philpem@5 17373 throw CImgInstanceException("CImg<%s>::HSItoRGB() : Input image dimension is dim=%u, "
philpem@5 17374 "should be a (H,S,I) image",
philpem@5 17375 pixel_type(),dim);
philpem@5 17376 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17377 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17378 Tfloat
philpem@5 17379 H = (Tfloat)*p1,
philpem@5 17380 S = (Tfloat)*p2,
philpem@5 17381 I = (Tfloat)*p3,
philpem@5 17382 a = I*(1-S),
philpem@5 17383 R = 0, G = 0, B = 0;
philpem@5 17384 if (H<120) {
philpem@5 17385 B = a;
philpem@5 17386 R = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
philpem@5 17387 G = 3*I-(R+B);
philpem@5 17388 } else if (H<240) {
philpem@5 17389 H-=120;
philpem@5 17390 R = a;
philpem@5 17391 G = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
philpem@5 17392 B = 3*I-(R+G);
philpem@5 17393 } else {
philpem@5 17394 H-=240;
philpem@5 17395 G = a;
philpem@5 17396 B = (Tfloat)(I*(1+S*cimg_std::cos(H*cimg::valuePI/180)/cimg_std::cos((60-H)*cimg::valuePI/180)));
philpem@5 17397 R = 3*I-(G+B);
philpem@5 17398 }
philpem@5 17399 R*=255; G*=255; B*=255;
philpem@5 17400 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17401 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17402 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17403 }
philpem@5 17404 return *this;
philpem@5 17405 }
philpem@5 17406
philpem@5 17407 CImg<Tfloat> get_HSItoRGB() const {
philpem@5 17408 return CImg< Tuchar>(*this,false).HSItoRGB();
philpem@5 17409 }
philpem@5 17410
philpem@5 17411 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
philpem@5 17412 CImg<T>& RGBtoYCbCr() {
philpem@5 17413 if (is_empty()) return *this;
philpem@5 17414 if (dim!=3)
philpem@5 17415 throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, "
philpem@5 17416 "should be a (R,G,B) image (dim=3)",
philpem@5 17417 pixel_type(),dim);
philpem@5 17418 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17419 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17420 const Tfloat
philpem@5 17421 R = (Tfloat)*p1,
philpem@5 17422 G = (Tfloat)*p2,
philpem@5 17423 B = (Tfloat)*p3,
philpem@5 17424 Y = (66*R + 129*G + 25*B + 128)/256 + 16,
philpem@5 17425 Cb = (-38*R - 74*G + 112*B + 128)/256 + 128,
philpem@5 17426 Cr = (112*R - 94*G - 18*B + 128)/256 + 128;
philpem@5 17427 *(p1++) = (T)(Y<0?0:(Y>255?255:Y));
philpem@5 17428 *(p2++) = (T)(Cb<0?0:(Cb>255?255:Cb));
philpem@5 17429 *(p3++) = (T)(Cr<0?0:(Cr>255?255:Cr));
philpem@5 17430 }
philpem@5 17431 return *this;
philpem@5 17432 }
philpem@5 17433
philpem@5 17434 CImg<Tuchar> get_RGBtoYCbCr() const {
philpem@5 17435 return CImg<Tuchar>(*this,false).RGBtoYCbCr();
philpem@5 17436 }
philpem@5 17437
philpem@5 17438 //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8.
philpem@5 17439 CImg<T>& YCbCrtoRGB() {
philpem@5 17440 if (is_empty()) return *this;
philpem@5 17441 if (dim!=3)
philpem@5 17442 throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, "
philpem@5 17443 "should be a (Y,Cb,Cr)_8 image (dim=3)",
philpem@5 17444 pixel_type(),dim);
philpem@5 17445 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17446 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17447 const Tfloat
philpem@5 17448 Y = (Tfloat)*p1 - 16,
philpem@5 17449 Cb = (Tfloat)*p2 - 128,
philpem@5 17450 Cr = (Tfloat)*p3 - 128,
philpem@5 17451 R = (298*Y + 409*Cr + 128)/256,
philpem@5 17452 G = (298*Y - 100*Cb - 208*Cr + 128)/256,
philpem@5 17453 B = (298*Y + 516*Cb + 128)/256;
philpem@5 17454 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17455 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17456 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17457 }
philpem@5 17458 return *this;
philpem@5 17459 }
philpem@5 17460
philpem@5 17461 CImg<Tuchar> get_YCbCrtoRGB() const {
philpem@5 17462 return CImg<Tuchar>(*this,false).YCbCrtoRGB();
philpem@5 17463 }
philpem@5 17464
philpem@5 17465 //! Convert color pixels from (R,G,B) to (Y,U,V).
philpem@5 17466 CImg<T>& RGBtoYUV() {
philpem@5 17467 if (is_empty()) return *this;
philpem@5 17468 if (dim!=3)
philpem@5 17469 throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, "
philpem@5 17470 "should be a (R,G,B) image (dim=3)",
philpem@5 17471 pixel_type(),dim);
philpem@5 17472 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17473 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17474 const Tfloat
philpem@5 17475 R = (Tfloat)*p1/255,
philpem@5 17476 G = (Tfloat)*p2/255,
philpem@5 17477 B = (Tfloat)*p3/255,
philpem@5 17478 Y = 0.299f*R + 0.587f*G + 0.114f*B;
philpem@5 17479 *(p1++) = (T)Y;
philpem@5 17480 *(p2++) = (T)(0.492f*(B-Y));
philpem@5 17481 *(p3++) = (T)(0.877*(R-Y));
philpem@5 17482 }
philpem@5 17483 return *this;
philpem@5 17484 }
philpem@5 17485
philpem@5 17486 CImg<Tfloat> get_RGBtoYUV() const {
philpem@5 17487 return CImg<Tfloat>(*this,false).RGBtoYUV();
philpem@5 17488 }
philpem@5 17489
philpem@5 17490 //! Convert color pixels from (Y,U,V) to (R,G,B).
philpem@5 17491 CImg<T>& YUVtoRGB() {
philpem@5 17492 if (is_empty()) return *this;
philpem@5 17493 if (dim!=3)
philpem@5 17494 throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, "
philpem@5 17495 "should be a (Y,U,V) image (dim=3)",
philpem@5 17496 pixel_type(),dim);
philpem@5 17497 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17498 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17499 const Tfloat
philpem@5 17500 Y = (Tfloat)*p1,
philpem@5 17501 U = (Tfloat)*p2,
philpem@5 17502 V = (Tfloat)*p3,
philpem@5 17503 R = (Y + 1.140f*V)*255,
philpem@5 17504 G = (Y - 0.395f*U - 0.581f*V)*255,
philpem@5 17505 B = (Y + 2.032f*U)*255;
philpem@5 17506 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17507 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17508 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17509 }
philpem@5 17510 return *this;
philpem@5 17511 }
philpem@5 17512
philpem@5 17513 CImg<Tuchar> get_YUVtoRGB() const {
philpem@5 17514 return CImg< Tuchar>(*this,false).YUVtoRGB();
philpem@5 17515 }
philpem@5 17516
philpem@5 17517 //! Convert color pixels from (R,G,B) to (C,M,Y).
philpem@5 17518 CImg<T>& RGBtoCMY() {
philpem@5 17519 if (is_empty()) return *this;
philpem@5 17520 if (dim!=3)
philpem@5 17521 throw CImgInstanceException("CImg<%s>::RGBtoCMY() : Input image dimension is dim=%u, "
philpem@5 17522 "should be a (R,G,B) image (dim=3)",
philpem@5 17523 pixel_type(),dim);
philpem@5 17524 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17525 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17526 const Tfloat
philpem@5 17527 R = (Tfloat)*p1/255,
philpem@5 17528 G = (Tfloat)*p2/255,
philpem@5 17529 B = (Tfloat)*p3/255;
philpem@5 17530 *(p1++) = (T)(1 - R);
philpem@5 17531 *(p2++) = (T)(1 - G);
philpem@5 17532 *(p3++) = (T)(1 - B);
philpem@5 17533 }
philpem@5 17534 return *this;
philpem@5 17535 }
philpem@5 17536
philpem@5 17537 CImg<Tfloat> get_RGBtoCMY() const {
philpem@5 17538 return CImg<Tfloat>(*this,false).RGBtoCMY();
philpem@5 17539 }
philpem@5 17540
philpem@5 17541 //! Convert (C,M,Y) pixels of a color image into the (R,G,B) color space.
philpem@5 17542 CImg<T>& CMYtoRGB() {
philpem@5 17543 if (is_empty()) return *this;
philpem@5 17544 if (dim!=3)
philpem@5 17545 throw CImgInstanceException("CImg<%s>::CMYtoRGB() : Input image dimension is dim=%u, "
philpem@5 17546 "should be a (C,M,Y) image (dim=3)",
philpem@5 17547 pixel_type(),dim);
philpem@5 17548 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17549 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17550 const Tfloat
philpem@5 17551 C = (Tfloat)*p1,
philpem@5 17552 M = (Tfloat)*p2,
philpem@5 17553 Y = (Tfloat)*p3,
philpem@5 17554 R = 255*(1 - C),
philpem@5 17555 G = 255*(1 - M),
philpem@5 17556 B = 255*(1 - Y);
philpem@5 17557 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17558 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17559 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17560 }
philpem@5 17561 return *this;
philpem@5 17562 }
philpem@5 17563
philpem@5 17564 CImg<Tuchar> get_CMYtoRGB() const {
philpem@5 17565 return CImg<Tuchar>(*this,false).CMYtoRGB();
philpem@5 17566 }
philpem@5 17567
philpem@5 17568 //! Convert color pixels from (C,M,Y) to (C,M,Y,K).
philpem@5 17569 CImg<T>& CMYtoCMYK() {
philpem@5 17570 return get_CMYtoCMYK().transfer_to(*this);
philpem@5 17571 }
philpem@5 17572
philpem@5 17573 CImg<Tfloat> get_CMYtoCMYK() const {
philpem@5 17574 if (is_empty()) return *this;
philpem@5 17575 if (dim!=3)
philpem@5 17576 throw CImgInstanceException("CImg<%s>::CMYtoCMYK() : Input image dimension is dim=%u, "
philpem@5 17577 "should be a (C,M,Y) image (dim=3)",
philpem@5 17578 pixel_type(),dim);
philpem@5 17579 CImg<Tfloat> res(width,height,depth,4);
philpem@5 17580 const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2);
philpem@5 17581 Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2), *pd4 = res.ptr(0,0,0,3);
philpem@5 17582 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17583 Tfloat
philpem@5 17584 C = (Tfloat)*(ps1++),
philpem@5 17585 M = (Tfloat)*(ps2++),
philpem@5 17586 Y = (Tfloat)*(ps3++),
philpem@5 17587 K = cimg::min(C,M,Y);
philpem@5 17588 if (K==1) C = M = Y = 0;
philpem@5 17589 else { const Tfloat K1 = 1 - K; C = (C - K)/K1; M = (M - K)/K1; Y = (Y - K)/K1; }
philpem@5 17590 *(pd1++) = C;
philpem@5 17591 *(pd2++) = M;
philpem@5 17592 *(pd3++) = Y;
philpem@5 17593 *(pd4++) = K;
philpem@5 17594 }
philpem@5 17595 return res;
philpem@5 17596 }
philpem@5 17597
philpem@5 17598 //! Convert (C,M,Y,K) pixels of a color image into the (C,M,Y) color space.
philpem@5 17599 CImg<T>& CMYKtoCMY() {
philpem@5 17600 return get_CMYKtoCMY().transfer_to(*this);
philpem@5 17601 }
philpem@5 17602
philpem@5 17603 CImg<Tfloat> get_CMYKtoCMY() const {
philpem@5 17604 if (is_empty()) return *this;
philpem@5 17605 if (dim!=4)
philpem@5 17606 throw CImgInstanceException("CImg<%s>::CMYKtoCMY() : Input image dimension is dim=%u, "
philpem@5 17607 "should be a (C,M,Y,K) image (dim=4)",
philpem@5 17608 pixel_type(),dim);
philpem@5 17609 CImg<Tfloat> res(width,height,depth,3);
philpem@5 17610 const T *ps1 = ptr(0,0,0,0), *ps2 = ptr(0,0,0,1), *ps3 = ptr(0,0,0,2), *ps4 = ptr(0,0,0,3);
philpem@5 17611 Tfloat *pd1 = res.ptr(0,0,0,0), *pd2 = res.ptr(0,0,0,1), *pd3 = res.ptr(0,0,0,2);
philpem@5 17612 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17613 const Tfloat
philpem@5 17614 C = (Tfloat)*ps1,
philpem@5 17615 M = (Tfloat)*ps2,
philpem@5 17616 Y = (Tfloat)*ps3,
philpem@5 17617 K = (Tfloat)*ps4,
philpem@5 17618 K1 = 1 - K;
philpem@5 17619 *(pd1++) = C*K1 + K;
philpem@5 17620 *(pd2++) = M*K1 + K;
philpem@5 17621 *(pd3++) = Y*K1 + K;
philpem@5 17622 }
philpem@5 17623 return res;
philpem@5 17624 }
philpem@5 17625
philpem@5 17626 //! Convert color pixels from (R,G,B) to (X,Y,Z)_709.
philpem@5 17627 CImg<T>& RGBtoXYZ() {
philpem@5 17628 if (is_empty()) return *this;
philpem@5 17629 if (dim!=3)
philpem@5 17630 throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, "
philpem@5 17631 "should be a (R,G,B) image (dim=3)",
philpem@5 17632 pixel_type(),dim);
philpem@5 17633 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17634 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17635 const Tfloat
philpem@5 17636 R = (Tfloat)*p1/255,
philpem@5 17637 G = (Tfloat)*p2/255,
philpem@5 17638 B = (Tfloat)*p3/255;
philpem@5 17639 *(p1++) = (T)(0.412453f*R + 0.357580f*G + 0.180423f*B);
philpem@5 17640 *(p2++) = (T)(0.212671f*R + 0.715160f*G + 0.072169f*B);
philpem@5 17641 *(p3++) = (T)(0.019334f*R + 0.119193f*G + 0.950227f*B);
philpem@5 17642 }
philpem@5 17643 return *this;
philpem@5 17644 }
philpem@5 17645
philpem@5 17646 CImg<Tfloat> get_RGBtoXYZ() const {
philpem@5 17647 return CImg<Tfloat>(*this,false).RGBtoXYZ();
philpem@5 17648 }
philpem@5 17649
philpem@5 17650 //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space.
philpem@5 17651 CImg<T>& XYZtoRGB() {
philpem@5 17652 if (is_empty()) return *this;
philpem@5 17653 if (dim!=3)
philpem@5 17654 throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, "
philpem@5 17655 "should be a (X,Y,Z) image (dim=3)",
philpem@5 17656 pixel_type(),dim);
philpem@5 17657 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17658 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17659 const Tfloat
philpem@5 17660 X = (Tfloat)*p1*255,
philpem@5 17661 Y = (Tfloat)*p2*255,
philpem@5 17662 Z = (Tfloat)*p3*255,
philpem@5 17663 R = 3.240479f*X - 1.537150f*Y - 0.498535f*Z,
philpem@5 17664 G = -0.969256f*X + 1.875992f*Y + 0.041556f*Z,
philpem@5 17665 B = 0.055648f*X - 0.204043f*Y + 1.057311f*Z;
philpem@5 17666 *(p1++) = (T)(R<0?0:(R>255?255:R));
philpem@5 17667 *(p2++) = (T)(G<0?0:(G>255?255:G));
philpem@5 17668 *(p3++) = (T)(B<0?0:(B>255?255:B));
philpem@5 17669 }
philpem@5 17670 return *this;
philpem@5 17671 }
philpem@5 17672
philpem@5 17673 CImg<Tuchar> get_XYZtoRGB() const {
philpem@5 17674 return CImg<Tuchar>(*this,false).XYZtoRGB();
philpem@5 17675 }
philpem@5 17676
philpem@5 17677 //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space.
philpem@5 17678 CImg<T>& XYZtoLab() {
philpem@5 17679 #define _cimg_Labf(x) ((x)>=0.008856f?(cimg_std::pow(x,(Tfloat)1/3)):(7.787f*(x)+16.0f/116))
philpem@5 17680 if (is_empty()) return *this;
philpem@5 17681 if (dim!=3)
philpem@5 17682 throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, "
philpem@5 17683 "should be a (X,Y,Z) image (dim=3)",
philpem@5 17684 pixel_type(),dim);
philpem@5 17685 const Tfloat
philpem@5 17686 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
philpem@5 17687 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
philpem@5 17688 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
philpem@5 17689 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17690 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17691 const Tfloat
philpem@5 17692 X = (Tfloat)*p1,
philpem@5 17693 Y = (Tfloat)*p2,
philpem@5 17694 Z = (Tfloat)*p3,
philpem@5 17695 XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn,
philpem@5 17696 fX = (Tfloat)_cimg_Labf(XXn),
philpem@5 17697 fY = (Tfloat)_cimg_Labf(YYn),
philpem@5 17698 fZ = (Tfloat)_cimg_Labf(ZZn);
philpem@5 17699 *(p1++) = (T)(116*fY - 16);
philpem@5 17700 *(p2++) = (T)(500*(fX - fY));
philpem@5 17701 *(p3++) = (T)(200*(fY - fZ));
philpem@5 17702 }
philpem@5 17703 return *this;
philpem@5 17704 }
philpem@5 17705
philpem@5 17706 CImg<Tfloat> get_XYZtoLab() const {
philpem@5 17707 return CImg<Tfloat>(*this,false).XYZtoLab();
philpem@5 17708 }
philpem@5 17709
philpem@5 17710 //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space.
philpem@5 17711 CImg<T>& LabtoXYZ() {
philpem@5 17712 #define _cimg_Labfi(x) ((x)>=0.206893f?((x)*(x)*(x)):(((x)-16.0f/116)/7.787f))
philpem@5 17713 if (is_empty()) return *this;
philpem@5 17714 if (dim!=3)
philpem@5 17715 throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, "
philpem@5 17716 "should be a (X,Y,Z) image (dim=3)",
philpem@5 17717 pixel_type(),dim);
philpem@5 17718 const Tfloat
philpem@5 17719 Xn = (Tfloat)(0.412453f + 0.357580f + 0.180423f),
philpem@5 17720 Yn = (Tfloat)(0.212671f + 0.715160f + 0.072169f),
philpem@5 17721 Zn = (Tfloat)(0.019334f + 0.119193f + 0.950227f);
philpem@5 17722 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17723 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17724 const Tfloat
philpem@5 17725 L = (Tfloat)*p1,
philpem@5 17726 a = (Tfloat)*p2,
philpem@5 17727 b = (Tfloat)*p3,
philpem@5 17728 cY = (L + 16)/116,
philpem@5 17729 Y = (Tfloat)(Yn*_cimg_Labfi(cY)),
philpem@5 17730 pY = (Tfloat)cimg_std::pow(Y/Yn,(Tfloat)1/3),
philpem@5 17731 cX = a/500 + pY,
philpem@5 17732 X = Xn*cX*cX*cX,
philpem@5 17733 cZ = pY - b/200,
philpem@5 17734 Z = Zn*cZ*cZ*cZ;
philpem@5 17735 *(p1++) = (T)(X);
philpem@5 17736 *(p2++) = (T)(Y);
philpem@5 17737 *(p3++) = (T)(Z);
philpem@5 17738 }
philpem@5 17739 return *this;
philpem@5 17740 }
philpem@5 17741
philpem@5 17742 CImg<Tfloat> get_LabtoXYZ() const {
philpem@5 17743 return CImg<Tfloat>(*this,false).LabtoXYZ();
philpem@5 17744 }
philpem@5 17745
philpem@5 17746 //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space.
philpem@5 17747 CImg<T>& XYZtoxyY() {
philpem@5 17748 if (is_empty()) return *this;
philpem@5 17749 if (dim!=3)
philpem@5 17750 throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, "
philpem@5 17751 "should be a (X,Y,Z) image (dim=3)",
philpem@5 17752 pixel_type(),dim);
philpem@5 17753 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17754 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17755 const Tfloat
philpem@5 17756 X = (Tfloat)*p1,
philpem@5 17757 Y = (Tfloat)*p2,
philpem@5 17758 Z = (Tfloat)*p3,
philpem@5 17759 sum = (X+Y+Z),
philpem@5 17760 nsum = sum>0?sum:1;
philpem@5 17761 *(p1++) = (T)(X/nsum);
philpem@5 17762 *(p2++) = (T)(Y/nsum);
philpem@5 17763 *(p3++) = (T)Y;
philpem@5 17764 }
philpem@5 17765 return *this;
philpem@5 17766 }
philpem@5 17767
philpem@5 17768 CImg<Tfloat> get_XYZtoxyY() const {
philpem@5 17769 return CImg<Tfloat>(*this,false).XYZtoxyY();
philpem@5 17770 }
philpem@5 17771
philpem@5 17772 //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space.
philpem@5 17773 CImg<T>& xyYtoXYZ() {
philpem@5 17774 if (is_empty()) return *this;
philpem@5 17775 if (dim!=3)
philpem@5 17776 throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, "
philpem@5 17777 "should be a (x,y,Y) image (dim=3)",
philpem@5 17778 pixel_type(),dim);
philpem@5 17779 T *p1 = ptr(0,0,0,0), *p2 = ptr(0,0,0,1), *p3 = ptr(0,0,0,2);
philpem@5 17780 for (unsigned long N = width*height*depth; N; --N) {
philpem@5 17781 const Tfloat
philpem@5 17782 px = (Tfloat)*p1,
philpem@5 17783 py = (Tfloat)*p2,
philpem@5 17784 Y = (Tfloat)*p3,
philpem@5 17785 ny = py>0?py:1;
philpem@5 17786 *(p1++) = (T)(px*Y/ny);
philpem@5 17787 *(p2++) = (T)Y;
philpem@5 17788 *(p3++) = (T)((1-px-py)*Y/ny);
philpem@5 17789 }
philpem@5 17790 return *this;
philpem@5 17791 }
philpem@5 17792
philpem@5 17793 CImg<Tfloat> get_xyYtoXYZ() const {
philpem@5 17794 return CImg<Tfloat>(*this,false).xyYtoXYZ();
philpem@5 17795 }
philpem@5 17796
philpem@5 17797 //! Convert a (R,G,B) image to a (L,a,b) one.
philpem@5 17798 CImg<T>& RGBtoLab() {
philpem@5 17799 return RGBtoXYZ().XYZtoLab();
philpem@5 17800 }
philpem@5 17801
philpem@5 17802 CImg<Tfloat> get_RGBtoLab() const {
philpem@5 17803 return CImg<Tfloat>(*this,false).RGBtoLab();
philpem@5 17804 }
philpem@5 17805
philpem@5 17806 //! Convert a (L,a,b) image to a (R,G,B) one.
philpem@5 17807 CImg<T>& LabtoRGB() {
philpem@5 17808 return LabtoXYZ().XYZtoRGB();
philpem@5 17809 }
philpem@5 17810
philpem@5 17811 CImg<Tuchar> get_LabtoRGB() const {
philpem@5 17812 return CImg<Tuchar>(*this,false).LabtoRGB();
philpem@5 17813 }
philpem@5 17814
philpem@5 17815 //! Convert a (R,G,B) image to a (x,y,Y) one.
philpem@5 17816 CImg<T>& RGBtoxyY() {
philpem@5 17817 return RGBtoXYZ().XYZtoxyY();
philpem@5 17818 }
philpem@5 17819
philpem@5 17820 CImg<Tfloat> get_RGBtoxyY() const {
philpem@5 17821 return CImg<Tfloat>(*this,false).RGBtoxyY();
philpem@5 17822 }
philpem@5 17823
philpem@5 17824 //! Convert a (x,y,Y) image to a (R,G,B) one.
philpem@5 17825 CImg<T>& xyYtoRGB() {
philpem@5 17826 return xyYtoXYZ().XYZtoRGB();
philpem@5 17827 }
philpem@5 17828
philpem@5 17829 CImg<Tuchar> get_xyYtoRGB() const {
philpem@5 17830 return CImg<Tuchar>(*this,false).xyYtoRGB();
philpem@5 17831 }
philpem@5 17832
philpem@5 17833 //! Convert a (R,G,B) image to a (C,M,Y,K) one.
philpem@5 17834 CImg<T>& RGBtoCMYK() {
philpem@5 17835 return RGBtoCMY().CMYtoCMYK();
philpem@5 17836 }
philpem@5 17837
philpem@5 17838 CImg<Tfloat> get_RGBtoCMYK() const {
philpem@5 17839 return CImg<Tfloat>(*this,false).RGBtoCMYK();
philpem@5 17840 }
philpem@5 17841
philpem@5 17842 //! Convert a (C,M,Y,K) image to a (R,G,B) one.
philpem@5 17843 CImg<T>& CMYKtoRGB() {
philpem@5 17844 return CMYKtoCMY().CMYtoRGB();
philpem@5 17845 }
philpem@5 17846
philpem@5 17847 CImg<Tuchar> get_CMYKtoRGB() const {
philpem@5 17848 return CImg<Tuchar>(*this,false).CMYKtoRGB();
philpem@5 17849 }
philpem@5 17850
philpem@5 17851 //! Convert a (R,G,B) image to a Bayer-coded representation.
philpem@5 17852 /**
philpem@5 17853 \note First (upper-left) pixel if the red component of the pixel color.
philpem@5 17854 **/
philpem@5 17855 CImg<T>& RGBtoBayer() {
philpem@5 17856 return get_RGBtoBayer().transfer_to(*this);
philpem@5 17857 }
philpem@5 17858
philpem@5 17859 CImg<T> get_RGBtoBayer() const {
philpem@5 17860 if (is_empty()) return *this;
philpem@5 17861 if (dim!=3)
philpem@5 17862 throw CImgInstanceException("CImg<%s>::RGBtoBayer() : Input image dimension is dim=%u, "
philpem@5 17863 "should be a (R,G,B) image (dim=3)",
philpem@5 17864 pixel_type(),dim);
philpem@5 17865 CImg<T> res(width,height,depth,1);
philpem@5 17866 const T *pR = ptr(0,0,0,0), *pG = ptr(0,0,0,1), *pB = ptr(0,0,0,2);
philpem@5 17867 T *ptrd = res.data;
philpem@5 17868 cimg_forXYZ(*this,x,y,z) {
philpem@5 17869 if (y%2) {
philpem@5 17870 if (x%2) *(ptrd++) = *pB;
philpem@5 17871 else *(ptrd++) = *pG;
philpem@5 17872 } else {
philpem@5 17873 if (x%2) *(ptrd++) = *pG;
philpem@5 17874 else *(ptrd++) = *pR;
philpem@5 17875 }
philpem@5 17876 ++pR; ++pG; ++pB;
philpem@5 17877 }
philpem@5 17878 return res;
philpem@5 17879 }
philpem@5 17880
philpem@5 17881 //! Convert a Bayer-coded image to a (R,G,B) color image.
philpem@5 17882 CImg<T>& BayertoRGB(const unsigned int interpolation_type=3) {
philpem@5 17883 return get_BayertoRGB(interpolation_type).transfer_to(*this);
philpem@5 17884 }
philpem@5 17885
philpem@5 17886 CImg<Tuchar> get_BayertoRGB(const unsigned int interpolation_type=3) const {
philpem@5 17887 if (is_empty()) return *this;
philpem@5 17888 if (dim!=1)
philpem@5 17889 throw CImgInstanceException("CImg<%s>::BayertoRGB() : Input image dimension is dim=%u, "
philpem@5 17890 "should be a Bayer image (dim=1)",
philpem@5 17891 pixel_type(),dim);
philpem@5 17892 CImg<Tuchar> res(width,height,depth,3);
philpem@5 17893 CImg_3x3(I,T);
philpem@5 17894 Tuchar *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2);
philpem@5 17895 switch (interpolation_type) {
philpem@5 17896 case 3 : { // Edge-directed
philpem@5 17897 CImg_3x3(R,T);
philpem@5 17898 CImg_3x3(G,T);
philpem@5 17899 CImg_3x3(B,T);
philpem@5 17900 cimg_forXYZ(*this,x,y,z) {
philpem@5 17901 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
philpem@5 17902 cimg_get3x3(*this,x,y,z,0,I);
philpem@5 17903 if (y%2) {
philpem@5 17904 if (x%2) {
philpem@5 17905 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
philpem@5 17906 *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
philpem@5 17907 } else *pG = (Tuchar)Icc;
philpem@5 17908 } else {
philpem@5 17909 if (x%2) *pG = (Tuchar)Icc;
philpem@5 17910 else {
philpem@5 17911 const Tfloat alpha = cimg::sqr((Tfloat)Inc - Ipc), beta = cimg::sqr((Tfloat)Icn - Icp), cx = 1/(1+alpha), cy = 1/(1+beta);
philpem@5 17912 *pG = (Tuchar)((cx*(Inc+Ipc) + cy*(Icn+Icp))/(2*(cx+cy)));
philpem@5 17913 }
philpem@5 17914 }
philpem@5 17915 ++pG;
philpem@5 17916 }
philpem@5 17917 cimg_forXYZ(*this,x,y,z) {
philpem@5 17918 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
philpem@5 17919 cimg_get3x3(*this,x,y,z,0,I);
philpem@5 17920 cimg_get3x3(res,x,y,z,1,G);
philpem@5 17921 if (y%2) {
philpem@5 17922 if (x%2) *pB = (Tuchar)Icc;
philpem@5 17923 else { *pR = (Tuchar)((Icn+Icp)/2); *pB = (Tuchar)((Inc+Ipc)/2); }
philpem@5 17924 } else {
philpem@5 17925 if (x%2) { *pR = (Tuchar)((Inc+Ipc)/2); *pB = (Tuchar)((Icn+Icp)/2); }
philpem@5 17926 else *pR = (Tuchar)Icc;
philpem@5 17927 }
philpem@5 17928 ++pR; ++pB;
philpem@5 17929 }
philpem@5 17930 pR = res.ptr(0,0,0,0);
philpem@5 17931 pG = res.ptr(0,0,0,1);
philpem@5 17932 pB = res.ptr(0,0,0,2);
philpem@5 17933 cimg_forXYZ(*this,x,y,z) {
philpem@5 17934 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
philpem@5 17935 cimg_get3x3(res,x,y,z,0,R);
philpem@5 17936 cimg_get3x3(res,x,y,z,1,G);
philpem@5 17937 cimg_get3x3(res,x,y,z,2,B);
philpem@5 17938 if (y%2) {
philpem@5 17939 if (x%2) {
philpem@5 17940 const float alpha = (float)cimg::sqr(Rnc-Rpc), beta = (float)cimg::sqr(Rcn-Rcp), cx = 1/(1+alpha), cy = 1/(1+beta);
philpem@5 17941 *pR = (Tuchar)((cx*(Rnc+Rpc) + cy*(Rcn+Rcp))/(2*(cx+cy)));
philpem@5 17942 }
philpem@5 17943 } else {
philpem@5 17944 if (!(x%2)) {
philpem@5 17945 const float alpha = (float)cimg::sqr(Bnc-Bpc), beta = (float)cimg::sqr(Bcn-Bcp), cx = 1/(1+alpha), cy = 1/(1+beta);
philpem@5 17946 *pB = (Tuchar)((cx*(Bnc+Bpc) + cy*(Bcn+Bcp))/(2*(cx+cy)));
philpem@5 17947 }
philpem@5 17948 }
philpem@5 17949 ++pR; ++pG; ++pB;
philpem@5 17950 }
philpem@5 17951 } break;
philpem@5 17952 case 2 : { // Linear interpolation
philpem@5 17953 cimg_forXYZ(*this,x,y,z) {
philpem@5 17954 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
philpem@5 17955 cimg_get3x3(*this,x,y,z,0,I);
philpem@5 17956 if (y%2) {
philpem@5 17957 if (x%2) { *pR = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)Icc; }
philpem@5 17958 else { *pR = (Tuchar)((Icp+Icn)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Inc+Ipc)/2); }
philpem@5 17959 } else {
philpem@5 17960 if (x%2) { *pR = (Tuchar)((Ipc+Inc)/2); *pG = (Tuchar)Icc; *pB = (Tuchar)((Icn+Icp)/2); }
philpem@5 17961 else { *pR = (Tuchar)Icc; *pG = (Tuchar)((Inc+Ipc+Icn+Icp)/4); *pB = (Tuchar)((Ipp+Inn+Ipn+Inp)/4); }
philpem@5 17962 }
philpem@5 17963 ++pR; ++pG; ++pB;
philpem@5 17964 }
philpem@5 17965 } break;
philpem@5 17966 case 1 : { // Nearest neighbor interpolation
philpem@5 17967 cimg_forXYZ(*this,x,y,z) {
philpem@5 17968 const int _p1x = x?x-1:1, _p1y = y?y-1:1, _n1x = x<dimx()-1?x+1:x-1, _n1y = y<dimy()-1?y+1:y-1;
philpem@5 17969 cimg_get3x3(*this,x,y,z,0,I);
philpem@5 17970 if (y%2) {
philpem@5 17971 if (x%2) { *pR = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)Icc; }
philpem@5 17972 else { *pR = (Tuchar)cimg::min(Icn,Icp); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Inc,Ipc); }
philpem@5 17973 } else {
philpem@5 17974 if (x%2) { *pR = (Tuchar)cimg::min(Inc,Ipc); *pG = (Tuchar)Icc; *pB = (Tuchar)cimg::min(Icn,Icp); }
philpem@5 17975 else { *pR = (Tuchar)Icc; *pG = (Tuchar)cimg::min(Inc,Ipc,Icn,Icp); *pB = (Tuchar)cimg::min(Ipp,Inn,Ipn,Inp); }
philpem@5 17976 }
philpem@5 17977 ++pR; ++pG; ++pB;
philpem@5 17978 }
philpem@5 17979 } break;
philpem@5 17980 default : { // 0-filling interpolation
philpem@5 17981 const T *ptrs = data;
philpem@5 17982 res.fill(0);
philpem@5 17983 cimg_forXYZ(*this,x,y,z) {
philpem@5 17984 const T val = *(ptrs++);
philpem@5 17985 if (y%2) { if (x%2) *pB = val; else *pG = val; } else { if (x%2) *pG = val; else *pR = val; }
philpem@5 17986 ++pR; ++pG; ++pB;
philpem@5 17987 }
philpem@5 17988 }
philpem@5 17989 }
philpem@5 17990 return res;
philpem@5 17991 }
philpem@5 17992
philpem@5 17993 //@}
philpem@5 17994 //-------------------
philpem@5 17995 //
philpem@5 17996 //! \name Drawing
philpem@5 17997 //@{
philpem@5 17998 //-------------------
philpem@5 17999
philpem@5 18000 // The following _draw_scanline() routines are *non user-friendly functions*, used only for internal purpose.
philpem@5 18001 // Pre-requisites : x0<x1, y-coordinate is valid, col is valid.
philpem@5 18002 template<typename tc>
philpem@5 18003 CImg<T>& _draw_scanline(const int x0, const int x1, const int y,
philpem@5 18004 const tc *const color, const float opacity=1,
philpem@5 18005 const float brightness=1, const bool init=false) {
philpem@5 18006 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 18007 static float nopacity = 0, copacity = 0;
philpem@5 18008 static unsigned int whz = 0;
philpem@5 18009 static const tc *col = 0;
philpem@5 18010 if (init) {
philpem@5 18011 nopacity = cimg::abs(opacity);
philpem@5 18012 copacity = 1 - cimg::max(opacity,0);
philpem@5 18013 whz = width*height*depth;
philpem@5 18014 } else {
philpem@5 18015 const int nx0 = x0>0?x0:0, nx1 = x1<dimx()?x1:dimx()-1, dx = nx1 - nx0;
philpem@5 18016 if (dx>=0) {
philpem@5 18017 col = color;
philpem@5 18018 const unsigned int off = whz-dx-1;
philpem@5 18019 T *ptrd = ptr(nx0,y);
philpem@5 18020 if (opacity>=1) { // ** Opaque drawing **
philpem@5 18021 if (brightness==1) { // Brightness==1
philpem@5 18022 if (sizeof(T)!=1) cimg_forV(*this,k) {
philpem@5 18023 const T val = (T)*(col++);
philpem@5 18024 for (int x = dx; x>=0; --x) *(ptrd++) = val;
philpem@5 18025 ptrd+=off;
philpem@5 18026 } else cimg_forV(*this,k) {
philpem@5 18027 const T val = (T)*(col++);
philpem@5 18028 cimg_std::memset(ptrd,(int)val,dx+1);
philpem@5 18029 ptrd+=whz;
philpem@5 18030 }
philpem@5 18031 } else if (brightness<1) { // Brightness<1
philpem@5 18032 if (sizeof(T)!=1) cimg_forV(*this,k) {
philpem@5 18033 const T val = (T)(*(col++)*brightness);
philpem@5 18034 for (int x = dx; x>=0; --x) *(ptrd++) = val;
philpem@5 18035 ptrd+=off;
philpem@5 18036 } else cimg_forV(*this,k) {
philpem@5 18037 const T val = (T)(*(col++)*brightness);
philpem@5 18038 cimg_std::memset(ptrd,(int)val,dx+1);
philpem@5 18039 ptrd+=whz;
philpem@5 18040 }
philpem@5 18041 } else { // Brightness>1
philpem@5 18042 if (sizeof(T)!=1) cimg_forV(*this,k) {
philpem@5 18043 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
philpem@5 18044 for (int x = dx; x>=0; --x) *(ptrd++) = val;
philpem@5 18045 ptrd+=off;
philpem@5 18046 } else cimg_forV(*this,k) {
philpem@5 18047 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
philpem@5 18048 cimg_std::memset(ptrd,(int)val,dx+1);
philpem@5 18049 ptrd+=whz;
philpem@5 18050 }
philpem@5 18051 }
philpem@5 18052 } else { // ** Transparent drawing **
philpem@5 18053 if (brightness==1) { // Brightness==1
philpem@5 18054 cimg_forV(*this,k) {
philpem@5 18055 const T val = (T)*(col++);
philpem@5 18056 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
philpem@5 18057 ptrd+=off;
philpem@5 18058 }
philpem@5 18059 } else if (brightness<=1) { // Brightness<1
philpem@5 18060 cimg_forV(*this,k) {
philpem@5 18061 const T val = (T)(*(col++)*brightness);
philpem@5 18062 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
philpem@5 18063 ptrd+=off;
philpem@5 18064 }
philpem@5 18065 } else { // Brightness>1
philpem@5 18066 cimg_forV(*this,k) {
philpem@5 18067 const T val = (T)((2-brightness)**(col++) + (brightness-1)*maxval);
philpem@5 18068 for (int x = dx; x>=0; --x) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ++ptrd; }
philpem@5 18069 ptrd+=off;
philpem@5 18070 }
philpem@5 18071 }
philpem@5 18072 }
philpem@5 18073 }
philpem@5 18074 }
philpem@5 18075 return *this;
philpem@5 18076 }
philpem@5 18077
philpem@5 18078 template<typename tc>
philpem@5 18079 CImg<T>& _draw_scanline(const tc *const color, const float opacity=1) {
philpem@5 18080 return _draw_scanline(0,0,0,color,opacity,0,true);
philpem@5 18081 }
philpem@5 18082
philpem@5 18083 //! Draw a 2D colored point (pixel).
philpem@5 18084 /**
philpem@5 18085 \param x0 X-coordinate of the point.
philpem@5 18086 \param y0 Y-coordinate of the point.
philpem@5 18087 \param color Pointer to \c dimv() consecutive values, defining the color values.
philpem@5 18088 \param opacity Drawing opacity (optional).
philpem@5 18089 \note
philpem@5 18090 - Clipping is supported.
philpem@5 18091 - To set pixel values without clipping needs, you should use the faster CImg::operator()() function.
philpem@5 18092 \par Example:
philpem@5 18093 \code
philpem@5 18094 CImg<unsigned char> img(100,100,1,3,0);
philpem@5 18095 const unsigned char color[] = { 255,128,64 };
philpem@5 18096 img.draw_point(50,50,color);
philpem@5 18097 \endcode
philpem@5 18098 **/
philpem@5 18099 template<typename tc>
philpem@5 18100 CImg<T>& draw_point(const int x0, const int y0,
philpem@5 18101 const tc *const color, const float opacity=1) {
philpem@5 18102 return draw_point(x0,y0,0,color,opacity);
philpem@5 18103 }
philpem@5 18104
philpem@5 18105 //! Draw a 2D colored point (pixel).
philpem@5 18106 template<typename tc>
philpem@5 18107 CImg<T>& draw_point(const int x0, const int y0,
philpem@5 18108 const CImg<tc>& color, const float opacity=1) {
philpem@5 18109 return draw_point(x0,y0,color.data,opacity);
philpem@5 18110 }
philpem@5 18111
philpem@5 18112 //! Draw a 3D colored point (voxel).
philpem@5 18113 template<typename tc>
philpem@5 18114 CImg<T>& draw_point(const int x0, const int y0, const int z0,
philpem@5 18115 const tc *const color, const float opacity=1) {
philpem@5 18116 if (is_empty()) return *this;
philpem@5 18117 if (!color)
philpem@5 18118 throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",
philpem@5 18119 pixel_type());
philpem@5 18120 if (x0>=0 && y0>=0 && z0>=0 && x0<dimx() && y0<dimy() && z0<dimz()) {
philpem@5 18121 const unsigned int whz = width*height*depth;
philpem@5 18122 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18123 T *ptrd = ptr(x0,y0,z0,0);
philpem@5 18124 const tc *col = color;
philpem@5 18125 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
philpem@5 18126 else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
philpem@5 18127 }
philpem@5 18128 return *this;
philpem@5 18129 }
philpem@5 18130
philpem@5 18131 //! Draw a 3D colored point (voxel).
philpem@5 18132 template<typename tc>
philpem@5 18133 CImg<T>& draw_point(const int x0, const int y0, const int z0,
philpem@5 18134 const CImg<tc>& color, const float opacity=1) {
philpem@5 18135 return draw_point(x0,y0,z0,color.data,opacity);
philpem@5 18136 }
philpem@5 18137
philpem@5 18138 // Draw a cloud of colored point (internal).
philpem@5 18139 template<typename t, typename tc>
philpem@5 18140 CImg<T>& _draw_point(const t& points, const unsigned int W, const unsigned int H,
philpem@5 18141 const tc *const color, const float opacity) {
philpem@5 18142 if (is_empty() || !points || !W) return *this;
philpem@5 18143 switch (H) {
philpem@5 18144 case 0 : case 1 :
philpem@5 18145 throw CImgArgumentException("CImg<%s>::draw_point() : Given list of points is not valid.",
philpem@5 18146 pixel_type());
philpem@5 18147 case 2 : {
philpem@5 18148 for (unsigned int i = 0; i<W; ++i) {
philpem@5 18149 const int x = (int)points(i,0), y = (int)points(i,1);
philpem@5 18150 draw_point(x,y,color,opacity);
philpem@5 18151 }
philpem@5 18152 } break;
philpem@5 18153 default : {
philpem@5 18154 for (unsigned int i = 0; i<W; ++i) {
philpem@5 18155 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
philpem@5 18156 draw_point(x,y,z,color,opacity);
philpem@5 18157 }
philpem@5 18158 }
philpem@5 18159 }
philpem@5 18160 return *this;
philpem@5 18161 }
philpem@5 18162
philpem@5 18163 //! Draw a cloud of colored points.
philpem@5 18164 /**
philpem@5 18165 \param points Coordinates of vertices, stored as a list of vectors.
philpem@5 18166 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 18167 \param opacity Drawing opacity (optional).
philpem@5 18168 \note
philpem@5 18169 - This function uses several call to the single CImg::draw_point() procedure,
philpem@5 18170 depending on the vectors size in \p points.
philpem@5 18171 \par Example:
philpem@5 18172 \code
philpem@5 18173 CImg<unsigned char> img(100,100,1,3,0);
philpem@5 18174 const unsigned char color[] = { 255,128,64 };
philpem@5 18175 CImgList<int> points;
philpem@5 18176 points.insert(CImg<int>::vector(0,0)).
philpem@5 18177 .insert(CImg<int>::vector(70,10)).
philpem@5 18178 .insert(CImg<int>::vector(80,60)).
philpem@5 18179 .insert(CImg<int>::vector(10,90));
philpem@5 18180 img.draw_point(points,color);
philpem@5 18181 \endcode
philpem@5 18182 **/
philpem@5 18183 template<typename t, typename tc>
philpem@5 18184 CImg<T>& draw_point(const CImgList<t>& points,
philpem@5 18185 const tc *const color, const float opacity=1) {
philpem@5 18186 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
philpem@5 18187 return _draw_point(points,points.size,H,color,opacity);
philpem@5 18188 }
philpem@5 18189
philpem@5 18190 //! Draw a cloud of colored points.
philpem@5 18191 template<typename t, typename tc>
philpem@5 18192 CImg<T>& draw_point(const CImgList<t>& points,
philpem@5 18193 const CImg<tc>& color, const float opacity=1) {
philpem@5 18194 return draw_point(points,color.data,opacity);
philpem@5 18195 }
philpem@5 18196
philpem@5 18197 //! Draw a cloud of colored points.
philpem@5 18198 /**
philpem@5 18199 \note
philpem@5 18200 - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
philpem@5 18201 (sequence of vectors aligned along the x-axis).
philpem@5 18202 **/
philpem@5 18203 template<typename t, typename tc>
philpem@5 18204 CImg<T>& draw_point(const CImg<t>& points,
philpem@5 18205 const tc *const color, const float opacity=1) {
philpem@5 18206 return _draw_point(points,points.width,points.height,color,opacity);
philpem@5 18207 }
philpem@5 18208
philpem@5 18209 //! Draw a cloud of colored points.
philpem@5 18210 template<typename t, typename tc>
philpem@5 18211 CImg<T>& draw_point(const CImg<t>& points,
philpem@5 18212 const CImg<tc>& color, const float opacity=1) {
philpem@5 18213 return draw_point(points,color.data,opacity);
philpem@5 18214 }
philpem@5 18215
philpem@5 18216 //! Draw a 2D colored line.
philpem@5 18217 /**
philpem@5 18218 \param x0 X-coordinate of the starting line point.
philpem@5 18219 \param y0 Y-coordinate of the starting line point.
philpem@5 18220 \param x1 X-coordinate of the ending line point.
philpem@5 18221 \param y1 Y-coordinate of the ending line point.
philpem@5 18222 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 18223 \param opacity Drawing opacity (optional).
philpem@5 18224 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 18225 \param init_hatch Flag telling if a reinitialization of the hash state must be done (optional).
philpem@5 18226 \note
philpem@5 18227 - Clipping is supported.
philpem@5 18228 - Line routine uses Bresenham's algorithm.
philpem@5 18229 - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern.
philpem@5 18230 \par Example:
philpem@5 18231 \code
philpem@5 18232 CImg<unsigned char> img(100,100,1,3,0);
philpem@5 18233 const unsigned char color[] = { 255,128,64 };
philpem@5 18234 img.draw_line(40,40,80,70,color);
philpem@5 18235 \endcode
philpem@5 18236 **/
philpem@5 18237 template<typename tc>
philpem@5 18238 CImg<T>& draw_line(const int x0, const int y0,
philpem@5 18239 const int x1, const int y1,
philpem@5 18240 const tc *const color, const float opacity=1,
philpem@5 18241 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18242 if (is_empty()) return *this;
philpem@5 18243 if (!color)
philpem@5 18244 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
philpem@5 18245 pixel_type());
philpem@5 18246 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18247 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18248 const bool xdir = x0<x1, ydir = y0<y1;
philpem@5 18249 int
philpem@5 18250 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
philpem@5 18251 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
philpem@5 18252 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
philpem@5 18253 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
philpem@5 18254 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
philpem@5 18255 if (xright<0 || xleft>=dimx()) return *this;
philpem@5 18256 if (xleft<0) { yleft-=xleft*(yright - yleft)/(xright - xleft); xleft = 0; }
philpem@5 18257 if (xright>=dimx()) { yright-=(xright - dimx())*(yright - yleft)/(xright - xleft); xright = dimx()-1; }
philpem@5 18258 if (ydown<0 || yup>=dimy()) return *this;
philpem@5 18259 if (yup<0) { xup-=yup*(xdown - xup)/(ydown - yup); yup = 0; }
philpem@5 18260 if (ydown>=dimy()) { xdown-=(ydown - dimy())*(xdown - xup)/(ydown - yup); ydown = dimy()-1; }
philpem@5 18261 T *ptrd0 = ptr(nx0,ny0);
philpem@5 18262 int dx = xright - xleft, dy = ydown - yup;
philpem@5 18263 const bool steep = dy>dx;
philpem@5 18264 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
philpem@5 18265 const int
philpem@5 18266 offx = (nx0<nx1?1:-1)*(steep?width:1),
philpem@5 18267 offy = (ny0<ny1?1:-1)*(steep?1:width),
philpem@5 18268 wh = width*height;
philpem@5 18269 if (opacity>=1) {
philpem@5 18270 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18271 if (pattern&hatch) { T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }}
philpem@5 18272 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18273 ptrd0+=offx;
philpem@5 18274 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18275 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18276 T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
philpem@5 18277 ptrd0+=offx;
philpem@5 18278 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18279 }
philpem@5 18280 } else {
philpem@5 18281 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18282 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18283 if (pattern&hatch) {
philpem@5 18284 T *ptrd = ptrd0; const tc* col = color;
philpem@5 18285 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18286 }
philpem@5 18287 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18288 ptrd0+=offx;
philpem@5 18289 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18290 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18291 T *ptrd = ptrd0; const tc* col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18292 ptrd0+=offx;
philpem@5 18293 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18294 }
philpem@5 18295 }
philpem@5 18296 return *this;
philpem@5 18297 }
philpem@5 18298
philpem@5 18299 //! Draw a 2D colored line.
philpem@5 18300 template<typename tc>
philpem@5 18301 CImg<T>& draw_line(const int x0, const int y0,
philpem@5 18302 const int x1, const int y1,
philpem@5 18303 const CImg<tc>& color, const float opacity=1,
philpem@5 18304 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18305 return draw_line(x0,y0,x1,y1,color.data,opacity,pattern,init_hatch);
philpem@5 18306 }
philpem@5 18307
philpem@5 18308 //! Draw a 2D colored line, with z-buffering.
philpem@5 18309 template<typename tc>
philpem@5 18310 CImg<T>& draw_line(float *const zbuffer,
philpem@5 18311 const int x0, const int y0, const float z0,
philpem@5 18312 const int x1, const int y1, const float z1,
philpem@5 18313 const tc *const color, const float opacity=1,
philpem@5 18314 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18315 if (!is_empty() && z0>0 && z1>0) {
philpem@5 18316 if (!color)
philpem@5 18317 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null).",
philpem@5 18318 pixel_type());
philpem@5 18319 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18320 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18321 const bool xdir = x0<x1, ydir = y0<y1;
philpem@5 18322 int
philpem@5 18323 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
philpem@5 18324 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
philpem@5 18325 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
philpem@5 18326 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
philpem@5 18327 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
philpem@5 18328 float
philpem@5 18329 Z0 = 1/z0, Z1 = 1/z1, nz0 = Z0, nz1 = Z1, dz = Z1 - Z0,
philpem@5 18330 &zleft = xdir?nz0:nz1,
philpem@5 18331 &zright = xdir?nz1:nz0,
philpem@5 18332 &zup = ydir?nz0:nz1,
philpem@5 18333 &zdown = ydir?nz1:nz0;
philpem@5 18334 if (xright<0 || xleft>=dimx()) return *this;
philpem@5 18335 if (xleft<0) {
philpem@5 18336 const int D = xright - xleft;
philpem@5 18337 yleft-=xleft*(yright - yleft)/D;
philpem@5 18338 zleft-=xleft*(zright - zleft)/D;
philpem@5 18339 xleft = 0;
philpem@5 18340 }
philpem@5 18341 if (xright>=dimx()) {
philpem@5 18342 const int d = xright - dimx(), D = xright - xleft;
philpem@5 18343 yright-=d*(yright - yleft)/D;
philpem@5 18344 zright-=d*(zright - zleft)/D;
philpem@5 18345 xright = dimx()-1;
philpem@5 18346 }
philpem@5 18347 if (ydown<0 || yup>=dimy()) return *this;
philpem@5 18348 if (yup<0) {
philpem@5 18349 const int D = ydown - yup;
philpem@5 18350 xup-=yup*(xdown - xup)/D;
philpem@5 18351 zup-=yup*(zdown - zup)/D;
philpem@5 18352 yup = 0;
philpem@5 18353 }
philpem@5 18354 if (ydown>=dimy()) {
philpem@5 18355 const int d = ydown - dimy(), D = ydown - yup;
philpem@5 18356 xdown-=d*(xdown - xup)/D;
philpem@5 18357 zdown-=d*(zdown - zup)/D;
philpem@5 18358 ydown = dimy()-1;
philpem@5 18359 }
philpem@5 18360 T *ptrd0 = ptr(nx0,ny0);
philpem@5 18361 float *ptrz = zbuffer + nx0 + ny0*width;
philpem@5 18362 int dx = xright - xleft, dy = ydown - yup;
philpem@5 18363 const bool steep = dy>dx;
philpem@5 18364 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
philpem@5 18365 const int
philpem@5 18366 offx = (nx0<nx1?1:-1)*(steep?width:1),
philpem@5 18367 offy = (ny0<ny1?1:-1)*(steep?1:width),
philpem@5 18368 wh = width*height,
philpem@5 18369 ndx = dx>0?dx:1;
philpem@5 18370 if (opacity>=1) {
philpem@5 18371 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18372 const float z = Z0 + x*dz/ndx;
philpem@5 18373 if (z>*ptrz && pattern&hatch) {
philpem@5 18374 *ptrz = z;
philpem@5 18375 T *ptrd = ptrd0; const tc *col = color;
philpem@5 18376 cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
philpem@5 18377 }
philpem@5 18378 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18379 ptrd0+=offx; ptrz+=offx;
philpem@5 18380 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18381 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18382 const float z = Z0 + x*dz/ndx;
philpem@5 18383 if (z>*ptrz) {
philpem@5 18384 *ptrz = z;
philpem@5 18385 T *ptrd = ptrd0; const tc *col = color;
philpem@5 18386 cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=wh; }
philpem@5 18387 }
philpem@5 18388 ptrd0+=offx; ptrz+=offx;
philpem@5 18389 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18390 }
philpem@5 18391 } else {
philpem@5 18392 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18393 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18394 const float z = Z0 + x*dz/ndx;
philpem@5 18395 if (z>*ptrz && pattern&hatch) {
philpem@5 18396 *ptrz = z;
philpem@5 18397 T *ptrd = ptrd0; const tc *col = color;
philpem@5 18398 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18399 }
philpem@5 18400 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18401 ptrd0+=offx; ptrz+=offx;
philpem@5 18402 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18403 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18404 const float z = Z0 + x*dz/ndx;
philpem@5 18405 if (z>*ptrz) {
philpem@5 18406 *ptrz = z;
philpem@5 18407 T *ptrd = ptrd0; const tc *col = color;
philpem@5 18408 cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18409 }
philpem@5 18410 ptrd0+=offx; ptrz+=offx;
philpem@5 18411 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18412 }
philpem@5 18413 }
philpem@5 18414 }
philpem@5 18415 return *this;
philpem@5 18416 }
philpem@5 18417
philpem@5 18418 //! Draw a 2D colored line, with z-buffering.
philpem@5 18419 template<typename tc>
philpem@5 18420 CImg<T>& draw_line(float *const zbuffer,
philpem@5 18421 const int x0, const int y0, const float z0,
philpem@5 18422 const int x1, const int y1, const float z1,
philpem@5 18423 const CImg<tc>& color, const float opacity=1,
philpem@5 18424 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18425 return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
philpem@5 18426 }
philpem@5 18427
philpem@5 18428 //! Draw a 3D colored line.
philpem@5 18429 template<typename tc>
philpem@5 18430 CImg<T>& draw_line(const int x0, const int y0, const int z0,
philpem@5 18431 const int x1, const int y1, const int z1,
philpem@5 18432 const tc *const color, const float opacity=1,
philpem@5 18433 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18434 if (is_empty()) return *this;
philpem@5 18435 if (!color)
philpem@5 18436 throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",
philpem@5 18437 pixel_type());
philpem@5 18438 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18439 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18440 int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1;
philpem@5 18441 if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
philpem@5 18442 if (nx1<0 || nx0>=dimx()) return *this;
philpem@5 18443 if (nx0<0) { const int D = 1 + nx1 - nx0; ny0-=nx0*(1 + ny1 - ny0)/D; nz0-=nx0*(1 + nz1 - nz0)/D; nx0 = 0; }
philpem@5 18444 if (nx1>=dimx()) { const int d = nx1-dimx(), D = 1 + nx1 - nx0; ny1+=d*(1 + ny0 - ny1)/D; nz1+=d*(1 + nz0 - nz1)/D; nx1 = dimx()-1; }
philpem@5 18445 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
philpem@5 18446 if (ny1<0 || ny0>=dimy()) return *this;
philpem@5 18447 if (ny0<0) { const int D = 1 + ny1 - ny0; nx0-=ny0*(1 + nx1 - nx0)/D; nz0-=ny0*(1 + nz1 - nz0)/D; ny0 = 0; }
philpem@5 18448 if (ny1>=dimy()) { const int d = ny1-dimy(), D = 1 + ny1 - ny0; nx1+=d*(1 + nx0 - nx1)/D; nz1+=d*(1 + nz0 - nz1)/D; ny1 = dimy()-1; }
philpem@5 18449 if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
philpem@5 18450 if (nz1<0 || nz0>=dimz()) return *this;
philpem@5 18451 if (nz0<0) { const int D = 1 + nz1 - nz0; nx0-=nz0*(1 + nx1 - nx0)/D; ny0-=nz0*(1 + ny1 - ny0)/D; nz0 = 0; }
philpem@5 18452 if (nz1>=dimz()) { const int d = nz1-dimz(), D = 1 + nz1 - nz0; nx1+=d*(1 + nx0 - nx1)/D; ny1+=d*(1 + ny0 - ny1)/D; nz1 = dimz()-1; }
philpem@5 18453 const unsigned int dmax = cimg::max(cimg::abs(nx1 - nx0),cimg::abs(ny1 - ny0),nz1 - nz0), whz = width*height*depth;
philpem@5 18454 const float px = (nx1 - nx0)/(float)dmax, py = (ny1 - ny0)/(float)dmax, pz = (nz1 - nz0)/(float)dmax;
philpem@5 18455 float x = (float)nx0, y = (float)ny0, z = (float)nz0;
philpem@5 18456 if (opacity>=1) for (unsigned int t = 0; t<=dmax; ++t) {
philpem@5 18457 if (!(~pattern) || (~pattern && pattern&hatch)) {
philpem@5 18458 T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
philpem@5 18459 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
philpem@5 18460 }
philpem@5 18461 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
philpem@5 18462 } else {
philpem@5 18463 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18464 for (unsigned int t = 0; t<=dmax; ++t) {
philpem@5 18465 if (!(~pattern) || (~pattern && pattern&hatch)) {
philpem@5 18466 T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z);
philpem@5 18467 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; }
philpem@5 18468 }
philpem@5 18469 x+=px; y+=py; z+=pz; if (pattern) { hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1); }
philpem@5 18470 }
philpem@5 18471 }
philpem@5 18472 return *this;
philpem@5 18473 }
philpem@5 18474
philpem@5 18475 //! Draw a 3D colored line.
philpem@5 18476 template<typename tc>
philpem@5 18477 CImg<T>& draw_line(const int x0, const int y0, const int z0,
philpem@5 18478 const int x1, const int y1, const int z1,
philpem@5 18479 const CImg<tc>& color, const float opacity=1,
philpem@5 18480 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18481 return draw_line(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern,init_hatch);
philpem@5 18482 }
philpem@5 18483
philpem@5 18484 //! Draw a 2D textured line.
philpem@5 18485 /**
philpem@5 18486 \param x0 X-coordinate of the starting line point.
philpem@5 18487 \param y0 Y-coordinate of the starting line point.
philpem@5 18488 \param x1 X-coordinate of the ending line point.
philpem@5 18489 \param y1 Y-coordinate of the ending line point.
philpem@5 18490 \param texture Texture image defining the pixel colors.
philpem@5 18491 \param tx0 X-coordinate of the starting texture point.
philpem@5 18492 \param ty0 Y-coordinate of the starting texture point.
philpem@5 18493 \param tx1 X-coordinate of the ending texture point.
philpem@5 18494 \param ty1 Y-coordinate of the ending texture point.
philpem@5 18495 \param opacity Drawing opacity (optional).
philpem@5 18496 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 18497 \param init_hatch Flag telling if the hash variable must be reinitialized (optional).
philpem@5 18498 \note
philpem@5 18499 - Clipping is supported but not for texture coordinates.
philpem@5 18500 - Line routine uses the well known Bresenham's algorithm.
philpem@5 18501 \par Example:
philpem@5 18502 \code
philpem@5 18503 CImg<unsigned char> img(100,100,1,3,0), texture("texture256x256.ppm");
philpem@5 18504 const unsigned char color[] = { 255,128,64 };
philpem@5 18505 img.draw_line(40,40,80,70,texture,0,0,255,255);
philpem@5 18506 \endcode
philpem@5 18507 **/
philpem@5 18508 template<typename tc>
philpem@5 18509 CImg<T>& draw_line(const int x0, const int y0,
philpem@5 18510 const int x1, const int y1,
philpem@5 18511 const CImg<tc>& texture,
philpem@5 18512 const int tx0, const int ty0,
philpem@5 18513 const int tx1, const int ty1,
philpem@5 18514 const float opacity=1,
philpem@5 18515 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18516 if (is_empty()) return *this;
philpem@5 18517 if (!texture || texture.dim<dim)
philpem@5 18518 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 18519 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 18520 if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
philpem@5 18521 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18522 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18523 const bool xdir = x0<x1, ydir = y0<y1;
philpem@5 18524 int
philpem@5 18525 dtx = tx1-tx0, dty = ty1-ty0,
philpem@5 18526 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
philpem@5 18527 tnx0 = tx0, tnx1 = tx1, tny0 = ty0, tny1 = ty1,
philpem@5 18528 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1, &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
philpem@5 18529 &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
philpem@5 18530 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1, &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0,
philpem@5 18531 &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
philpem@5 18532 if (xright<0 || xleft>=dimx()) return *this;
philpem@5 18533 if (xleft<0) {
philpem@5 18534 const int D = xright - xleft;
philpem@5 18535 yleft-=xleft*(yright - yleft)/D;
philpem@5 18536 txleft-=xleft*(txright - txleft)/D;
philpem@5 18537 tyleft-=xleft*(tyright - tyleft)/D;
philpem@5 18538 xleft = 0;
philpem@5 18539 }
philpem@5 18540 if (xright>=dimx()) {
philpem@5 18541 const int d = xright - dimx(), D = xright - xleft;
philpem@5 18542 yright-=d*(yright - yleft)/D;
philpem@5 18543 txright-=d*(txright - txleft)/D;
philpem@5 18544 tyright-=d*(tyright - tyleft)/D;
philpem@5 18545 xright = dimx()-1;
philpem@5 18546 }
philpem@5 18547 if (ydown<0 || yup>=dimy()) return *this;
philpem@5 18548 if (yup<0) {
philpem@5 18549 const int D = ydown - yup;
philpem@5 18550 xup-=yup*(xdown - xup)/D;
philpem@5 18551 txup-=yup*(txdown - txup)/D;
philpem@5 18552 tyup-=yup*(tydown - tyup)/D;
philpem@5 18553 yup = 0;
philpem@5 18554 }
philpem@5 18555 if (ydown>=dimy()) {
philpem@5 18556 const int d = ydown - dimy(), D = ydown - yup;
philpem@5 18557 xdown-=d*(xdown - xup)/D;
philpem@5 18558 txdown-=d*(txdown - txup)/D;
philpem@5 18559 tydown-=d*(tydown - tyup)/D;
philpem@5 18560 ydown = dimy()-1;
philpem@5 18561 }
philpem@5 18562 T *ptrd0 = ptr(nx0,ny0);
philpem@5 18563 int dx = xright - xleft, dy = ydown - yup;
philpem@5 18564 const bool steep = dy>dx;
philpem@5 18565 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
philpem@5 18566 const int
philpem@5 18567 offx = (nx0<nx1?1:-1)*(steep?width:1),
philpem@5 18568 offy = (ny0<ny1?1:-1)*(steep?1:width),
philpem@5 18569 wh = width*height,
philpem@5 18570 ndx = dx>0?dx:1;
philpem@5 18571 if (opacity>=1) {
philpem@5 18572 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18573 if (pattern&hatch) {
philpem@5 18574 T *ptrd = ptrd0;
philpem@5 18575 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
philpem@5 18576 cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
philpem@5 18577 }
philpem@5 18578 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18579 ptrd0+=offx;
philpem@5 18580 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18581 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18582 T *ptrd = ptrd0;
philpem@5 18583 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
philpem@5 18584 cimg_forV(*this,k) { *ptrd = (T)texture(tx,ty,0,k); ptrd+=wh; }
philpem@5 18585 ptrd0+=offx;
philpem@5 18586 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18587 }
philpem@5 18588 } else {
philpem@5 18589 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18590 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18591 T *ptrd = ptrd0;
philpem@5 18592 if (pattern&hatch) {
philpem@5 18593 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
philpem@5 18594 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18595 }
philpem@5 18596 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18597 ptrd0+=offx;
philpem@5 18598 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18599 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18600 T *ptrd = ptrd0;
philpem@5 18601 const int tx = tx0 + x*dtx/ndx, ty = ty0 + x*dty/ndx;
philpem@5 18602 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture(tx,ty,0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18603 ptrd0+=offx;
philpem@5 18604 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18605 }
philpem@5 18606 }
philpem@5 18607 return *this;
philpem@5 18608 }
philpem@5 18609
philpem@5 18610 //! Draw a 2D textured line, with perspective correction.
philpem@5 18611 template<typename tc>
philpem@5 18612 CImg<T>& draw_line(const int x0, const int y0, const float z0,
philpem@5 18613 const int x1, const int y1, const float z1,
philpem@5 18614 const CImg<tc>& texture,
philpem@5 18615 const int tx0, const int ty0,
philpem@5 18616 const int tx1, const int ty1,
philpem@5 18617 const float opacity=1,
philpem@5 18618 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18619 if (is_empty() && z0<=0 && z1<=0) return *this;
philpem@5 18620 if (!texture || texture.dim<dim)
philpem@5 18621 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 18622 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 18623 if (is_overlapped(texture)) return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
philpem@5 18624 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18625 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18626 const bool xdir = x0<x1, ydir = y0<y1;
philpem@5 18627 int
philpem@5 18628 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
philpem@5 18629 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
philpem@5 18630 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
philpem@5 18631 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
philpem@5 18632 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
philpem@5 18633 float
philpem@5 18634 Tx0 = tx0/z0, Tx1 = tx1/z1,
philpem@5 18635 Ty0 = ty0/z0, Ty1 = ty1/z1,
philpem@5 18636 Z0 = 1/z0, Z1 = 1/z1,
philpem@5 18637 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
philpem@5 18638 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
philpem@5 18639 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
philpem@5 18640 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
philpem@5 18641 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
philpem@5 18642 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
philpem@5 18643 if (xright<0 || xleft>=dimx()) return *this;
philpem@5 18644 if (xleft<0) {
philpem@5 18645 const int D = xright - xleft;
philpem@5 18646 yleft-=xleft*(yright - yleft)/D;
philpem@5 18647 zleft-=xleft*(zright - zleft)/D;
philpem@5 18648 txleft-=xleft*(txright - txleft)/D;
philpem@5 18649 tyleft-=xleft*(tyright - tyleft)/D;
philpem@5 18650 xleft = 0;
philpem@5 18651 }
philpem@5 18652 if (xright>=dimx()) {
philpem@5 18653 const int d = xright - dimx(), D = xright - xleft;
philpem@5 18654 yright-=d*(yright - yleft)/D;
philpem@5 18655 zright-=d*(zright - zleft)/D;
philpem@5 18656 txright-=d*(txright - txleft)/D;
philpem@5 18657 tyright-=d*(tyright - tyleft)/D;
philpem@5 18658 xright = dimx()-1;
philpem@5 18659 }
philpem@5 18660 if (ydown<0 || yup>=dimy()) return *this;
philpem@5 18661 if (yup<0) {
philpem@5 18662 const int D = ydown - yup;
philpem@5 18663 xup-=yup*(xdown - xup)/D;
philpem@5 18664 zup-=yup*(zdown - zup)/D;
philpem@5 18665 txup-=yup*(txdown - txup)/D;
philpem@5 18666 tyup-=yup*(tydown - tyup)/D;
philpem@5 18667 yup = 0;
philpem@5 18668 }
philpem@5 18669 if (ydown>=dimy()) {
philpem@5 18670 const int d = ydown - dimy(), D = ydown - yup;
philpem@5 18671 xdown-=d*(xdown - xup)/D;
philpem@5 18672 zdown-=d*(zdown - zup)/D;
philpem@5 18673 txdown-=d*(txdown - txup)/D;
philpem@5 18674 tydown-=d*(tydown - tyup)/D;
philpem@5 18675 ydown = dimy()-1;
philpem@5 18676 }
philpem@5 18677 T *ptrd0 = ptr(nx0,ny0);
philpem@5 18678 int dx = xright - xleft, dy = ydown - yup;
philpem@5 18679 const bool steep = dy>dx;
philpem@5 18680 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
philpem@5 18681 const int
philpem@5 18682 offx = (nx0<nx1?1:-1)*(steep?width:1),
philpem@5 18683 offy = (ny0<ny1?1:-1)*(steep?1:width),
philpem@5 18684 wh = width*height,
philpem@5 18685 ndx = dx>0?dx:1;
philpem@5 18686 if (opacity>=1) {
philpem@5 18687 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18688 if (pattern&hatch) {
philpem@5 18689 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18690 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
philpem@5 18691 }
philpem@5 18692 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18693 ptrd0+=offx;
philpem@5 18694 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18695 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18696 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18697 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
philpem@5 18698 ptrd0+=offx;
philpem@5 18699 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18700 }
philpem@5 18701 } else {
philpem@5 18702 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18703 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18704 if (pattern&hatch) {
philpem@5 18705 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18706 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18707 }
philpem@5 18708 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18709 ptrd0+=offx;
philpem@5 18710 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18711 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18712 const float z = Z0 + x*dz/ndx, tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18713 T *ptrd = ptrd0;
philpem@5 18714 cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18715 ptrd0+=offx;
philpem@5 18716 if ((error-=dy)<0) { ptrd0+=offy; error+=dx; }
philpem@5 18717 }
philpem@5 18718 }
philpem@5 18719 return *this;
philpem@5 18720 }
philpem@5 18721
philpem@5 18722 //! Draw a 2D textured line, with z-buffering and perspective correction.
philpem@5 18723 template<typename tc>
philpem@5 18724 CImg<T>& draw_line(float *const zbuffer,
philpem@5 18725 const int x0, const int y0, const float z0,
philpem@5 18726 const int x1, const int y1, const float z1,
philpem@5 18727 const CImg<tc>& texture,
philpem@5 18728 const int tx0, const int ty0,
philpem@5 18729 const int tx1, const int ty1,
philpem@5 18730 const float opacity=1,
philpem@5 18731 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18732 if (!is_empty() && z0>0 && z1>0) {
philpem@5 18733 if (!texture || texture.dim<dim)
philpem@5 18734 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 18735 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 18736 if (is_overlapped(texture)) return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch);
philpem@5 18737 static unsigned int hatch = ~0U - (~0U>>1);
philpem@5 18738 if (init_hatch) hatch = ~0U - (~0U>>1);
philpem@5 18739 const bool xdir = x0<x1, ydir = y0<y1;
philpem@5 18740 int
philpem@5 18741 nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1,
philpem@5 18742 &xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
philpem@5 18743 &xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
philpem@5 18744 &xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
philpem@5 18745 &xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
philpem@5 18746 float
philpem@5 18747 Tx0 = tx0/z0, Tx1 = tx1/z1,
philpem@5 18748 Ty0 = ty0/z0, Ty1 = ty1/z1,
philpem@5 18749 Z0 = 1/z0, Z1 = 1/z1,
philpem@5 18750 dz = Z1 - Z0, dtx = Tx1 - Tx0, dty = Ty1 - Ty0,
philpem@5 18751 tnx0 = Tx0, tnx1 = Tx1, tny0 = Ty0, tny1 = Ty1, nz0 = Z0, nz1 = Z1,
philpem@5 18752 &zleft = xdir?nz0:nz1, &txleft = xdir?tnx0:tnx1, &tyleft = xdir?tny0:tny1,
philpem@5 18753 &zright = xdir?nz1:nz0, &txright = xdir?tnx1:tnx0, &tyright = xdir?tny1:tny0,
philpem@5 18754 &zup = ydir?nz0:nz1, &txup = ydir?tnx0:tnx1, &tyup = ydir?tny0:tny1,
philpem@5 18755 &zdown = ydir?nz1:nz0, &txdown = ydir?tnx1:tnx0, &tydown = ydir?tny1:tny0;
philpem@5 18756 if (xright<0 || xleft>=dimx()) return *this;
philpem@5 18757 if (xleft<0) {
philpem@5 18758 const int D = xright - xleft;
philpem@5 18759 yleft-=xleft*(yright - yleft)/D;
philpem@5 18760 zleft-=xleft*(zright - zleft)/D;
philpem@5 18761 txleft-=xleft*(txright - txleft)/D;
philpem@5 18762 tyleft-=xleft*(tyright - tyleft)/D;
philpem@5 18763 xleft = 0;
philpem@5 18764 }
philpem@5 18765 if (xright>=dimx()) {
philpem@5 18766 const int d = xright - dimx(), D = xright - xleft;
philpem@5 18767 yright-=d*(yright - yleft)/D;
philpem@5 18768 zright-=d*(zright - zleft)/D;
philpem@5 18769 txright-=d*(txright - txleft)/D;
philpem@5 18770 tyright-=d*(tyright - tyleft)/D;
philpem@5 18771 xright = dimx()-1;
philpem@5 18772 }
philpem@5 18773 if (ydown<0 || yup>=dimy()) return *this;
philpem@5 18774 if (yup<0) {
philpem@5 18775 const int D = ydown - yup;
philpem@5 18776 xup-=yup*(xdown - xup)/D;
philpem@5 18777 zup-=yup*(zdown - zup)/D;
philpem@5 18778 txup-=yup*(txdown - txup)/D;
philpem@5 18779 tyup-=yup*(tydown - tyup)/D;
philpem@5 18780 yup = 0;
philpem@5 18781 }
philpem@5 18782 if (ydown>=dimy()) {
philpem@5 18783 const int d = ydown - dimy(), D = ydown - yup;
philpem@5 18784 xdown-=d*(xdown - xup)/D;
philpem@5 18785 zdown-=d*(zdown - zup)/D;
philpem@5 18786 txdown-=d*(txdown - txup)/D;
philpem@5 18787 tydown-=d*(tydown - tyup)/D;
philpem@5 18788 ydown = dimy()-1;
philpem@5 18789 }
philpem@5 18790 T *ptrd0 = ptr(nx0,ny0);
philpem@5 18791 float *ptrz = zbuffer + nx0 + ny0*width;
philpem@5 18792 int dx = xright - xleft, dy = ydown - yup;
philpem@5 18793 const bool steep = dy>dx;
philpem@5 18794 if (steep) cimg::swap(nx0,ny0,nx1,ny1,dx,dy);
philpem@5 18795 const int
philpem@5 18796 offx = (nx0<nx1?1:-1)*(steep?width:1),
philpem@5 18797 offy = (ny0<ny1?1:-1)*(steep?1:width),
philpem@5 18798 wh = width*height,
philpem@5 18799 ndx = dx>0?dx:1;
philpem@5 18800 if (opacity>=1) {
philpem@5 18801 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18802 if (pattern&hatch) {
philpem@5 18803 const float z = Z0 + x*dz/ndx;
philpem@5 18804 if (z>*ptrz) {
philpem@5 18805 *ptrz = z;
philpem@5 18806 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18807 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
philpem@5 18808 }
philpem@5 18809 }
philpem@5 18810 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18811 ptrd0+=offx; ptrz+=offx;
philpem@5 18812 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18813 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18814 const float z = Z0 + x*dz/ndx;
philpem@5 18815 if (z>*ptrz) {
philpem@5 18816 *ptrz = z;
philpem@5 18817 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18818 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)texture((int)(tx/z),(int)(ty/z),0,k); ptrd+=wh; }
philpem@5 18819 }
philpem@5 18820 ptrd0+=offx; ptrz+=offx;
philpem@5 18821 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18822 }
philpem@5 18823 } else {
philpem@5 18824 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 18825 if (~pattern) for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18826 if (pattern&hatch) {
philpem@5 18827 const float z = Z0 + x*dz/ndx;
philpem@5 18828 if (z>*ptrz) {
philpem@5 18829 *ptrz = z;
philpem@5 18830 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18831 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18832 }
philpem@5 18833 }
philpem@5 18834 hatch>>=1; if (!hatch) hatch = ~0U - (~0U>>1);
philpem@5 18835 ptrd0+=offx; ptrz+=offx;
philpem@5 18836 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offy; error+=dx; }
philpem@5 18837 } else for (int error = dx>>1, x = 0; x<=dx; ++x) {
philpem@5 18838 const float z = Z0 + x*dz/ndx;
philpem@5 18839 if (z>*ptrz) {
philpem@5 18840 *ptrz = z;
philpem@5 18841 const float tx = Tx0 + x*dtx/ndx, ty = Ty0 + x*dty/ndx;
philpem@5 18842 T *ptrd = ptrd0; cimg_forV(*this,k) { *ptrd = (T)(nopacity*texture((int)(tx/z),(int)(ty/z),0,k) + *ptrd*copacity); ptrd+=wh; }
philpem@5 18843 }
philpem@5 18844 ptrd0+=offx; ptrz+=offx;
philpem@5 18845 if ((error-=dy)<0) { ptrd0+=offy; ptrz+=offx; error+=dx; }
philpem@5 18846 }
philpem@5 18847 }
philpem@5 18848 }
philpem@5 18849 return *this;
philpem@5 18850 }
philpem@5 18851
philpem@5 18852 // Inner routine for drawing set of consecutive lines with generic type for coordinates.
philpem@5 18853 template<typename t, typename tc>
philpem@5 18854 CImg<T>& _draw_line(const t& points, const unsigned int W, const unsigned int H,
philpem@5 18855 const tc *const color, const float opacity,
philpem@5 18856 const unsigned int pattern, const bool init_hatch) {
philpem@5 18857 if (is_empty() || !points || W<2) return *this;
philpem@5 18858 bool ninit_hatch = init_hatch;
philpem@5 18859 switch (H) {
philpem@5 18860 case 0 : case 1 :
philpem@5 18861 throw CImgArgumentException("CImg<%s>::draw_line() : Given list of points is not valid.",
philpem@5 18862 pixel_type());
philpem@5 18863 case 2 : {
philpem@5 18864 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
philpem@5 18865 int ox = x0, oy = y0;
philpem@5 18866 for (unsigned int i = 1; i<W; ++i) {
philpem@5 18867 const int x = (int)points(i,0), y = (int)points(i,1);
philpem@5 18868 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
philpem@5 18869 ninit_hatch = false;
philpem@5 18870 ox = x; oy = y;
philpem@5 18871 }
philpem@5 18872 } break;
philpem@5 18873 default : {
philpem@5 18874 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
philpem@5 18875 int ox = x0, oy = y0, oz = z0;
philpem@5 18876 for (unsigned int i = 1; i<W; ++i) {
philpem@5 18877 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
philpem@5 18878 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
philpem@5 18879 ninit_hatch = false;
philpem@5 18880 ox = x; oy = y; oz = z;
philpem@5 18881 }
philpem@5 18882 }
philpem@5 18883 }
philpem@5 18884 return *this;
philpem@5 18885 }
philpem@5 18886
philpem@5 18887 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 18888 /**
philpem@5 18889 \param points Coordinates of vertices, stored as a list of vectors.
philpem@5 18890 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 18891 \param opacity Drawing opacity (optional).
philpem@5 18892 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 18893 \param init_hatch If set to true, init hatch motif.
philpem@5 18894 \note
philpem@5 18895 - This function uses several call to the single CImg::draw_line() procedure,
philpem@5 18896 depending on the vectors size in \p points.
philpem@5 18897 \par Example:
philpem@5 18898 \code
philpem@5 18899 CImg<unsigned char> img(100,100,1,3,0);
philpem@5 18900 const unsigned char color[] = { 255,128,64 };
philpem@5 18901 CImgList<int> points;
philpem@5 18902 points.insert(CImg<int>::vector(0,0)).
philpem@5 18903 .insert(CImg<int>::vector(70,10)).
philpem@5 18904 .insert(CImg<int>::vector(80,60)).
philpem@5 18905 .insert(CImg<int>::vector(10,90));
philpem@5 18906 img.draw_line(points,color);
philpem@5 18907 \endcode
philpem@5 18908 **/
philpem@5 18909 template<typename t, typename tc>
philpem@5 18910 CImg<T>& draw_line(const CImgList<t>& points,
philpem@5 18911 const tc *const color, const float opacity=1,
philpem@5 18912 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18913 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
philpem@5 18914 return _draw_line(points,points.size,H,color,opacity,pattern,init_hatch);
philpem@5 18915 }
philpem@5 18916
philpem@5 18917 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 18918 template<typename t, typename tc>
philpem@5 18919 CImg<T>& draw_line(const CImgList<t>& points,
philpem@5 18920 const CImg<tc>& color, const float opacity=1,
philpem@5 18921 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18922 return draw_line(points,color.data,opacity,pattern,init_hatch);
philpem@5 18923 }
philpem@5 18924
philpem@5 18925 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 18926 /**
philpem@5 18927 \note
philpem@5 18928 - Similar to the previous function, where the N vertex coordinates are stored as a Nx2 or Nx3 image
philpem@5 18929 (sequence of vectors aligned along the x-axis).
philpem@5 18930 **/
philpem@5 18931 template<typename t, typename tc>
philpem@5 18932 CImg<T>& draw_line(const CImg<t>& points,
philpem@5 18933 const tc *const color, const float opacity=1,
philpem@5 18934 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18935 return _draw_line(points,points.width,points.height,color,opacity,pattern,init_hatch);
philpem@5 18936 }
philpem@5 18937
philpem@5 18938 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 18939 template<typename t, typename tc>
philpem@5 18940 CImg<T>& draw_line(const CImg<t>& points,
philpem@5 18941 const CImg<tc>& color, const float opacity=1,
philpem@5 18942 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 18943 return draw_line(points,color.data,opacity,pattern,init_hatch);
philpem@5 18944 }
philpem@5 18945
philpem@5 18946 // Inner routine for a drawing filled polygon with generic type for coordinates.
philpem@5 18947 template<typename t, typename tc>
philpem@5 18948 CImg<T>& _draw_polygon(const t& points, const unsigned int N,
philpem@5 18949 const tc *const color, const float opacity) {
philpem@5 18950 if (is_empty() || !points || N<3) return *this;
philpem@5 18951 if (!color)
philpem@5 18952 throw CImgArgumentException("CImg<%s>::draw_polygon() : Specified color is (null).",
philpem@5 18953 pixel_type());
philpem@5 18954 _draw_scanline(color,opacity);
philpem@5 18955 int xmin = (int)(~0U>>1), xmax = 0, ymin = (int)(~0U>>1), ymax = 0;
philpem@5 18956 { for (unsigned int p = 0; p<N; ++p) {
philpem@5 18957 const int x = (int)points(p,0), y = (int)points(p,1);
philpem@5 18958 if (x<xmin) xmin = x;
philpem@5 18959 if (x>xmax) xmax = x;
philpem@5 18960 if (y<ymin) ymin = y;
philpem@5 18961 if (y>ymax) ymax = y;
philpem@5 18962 }}
philpem@5 18963 if (xmax<0 || xmin>=dimx() || ymax<0 || ymin>=dimy()) return *this;
philpem@5 18964 const unsigned int
philpem@5 18965 nymin = ymin<0?0:(unsigned int)ymin,
philpem@5 18966 nymax = ymax>=dimy()?height-1:(unsigned int)ymax,
philpem@5 18967 dy = 1 + nymax - nymin;
philpem@5 18968 CImg<intT> X(1+2*N,dy,1,1,0), tmp;
philpem@5 18969 int cx = (int)points(0,0), cy = (int)points(0,1);
philpem@5 18970 for (unsigned int cp = 0, p = 0; p<N; ++p) {
philpem@5 18971 const unsigned int np = (p!=N-1)?p+1:0, ap = (np!=N-1)?np+1:0;
philpem@5 18972 const int
philpem@5 18973 nx = (int)points(np,0), ny = (int)points(np,1), ay = (int)points(ap,1),
philpem@5 18974 y0 = cy - nymin, y1 = ny - nymin;
philpem@5 18975 if (y0!=y1) {
philpem@5 18976 const int countermin = ((ny<ay && cy<ny) || (ny>ay && cy>ny))?1:0;
philpem@5 18977 for (int x = cx, y = y0, _sx = 1, _sy = 1,
philpem@5 18978 _dx = nx>cx?nx-cx:((_sx=-1),cx-nx),
philpem@5 18979 _dy = y1>y0?y1-y0:((_sy=-1),y0-y1),
philpem@5 18980 _counter = ((_dx-=_dy?_dy*(_dx/_dy):0),_dy),
philpem@5 18981 _err = _dx>>1,
philpem@5 18982 _rx = _dy?(nx-cx)/_dy:0;
philpem@5 18983 _counter>=countermin;
philpem@5 18984 --_counter, y+=_sy, x+=_rx + ((_err-=_dx)<0?_err+=_dy,_sx:0))
philpem@5 18985 if (y>=0 && y<(int)dy) X(++X(0,y),y) = x;
philpem@5 18986 cp = np; cx = nx; cy = ny;
philpem@5 18987 } else {
philpem@5 18988 const int pp = (cp?cp-1:N-1), py = (int)points(pp,1);
philpem@5 18989 if ((cy>py && ay>cy) || (cy<py && ay<cy)) X(++X(0,y0),y0) = nx;
philpem@5 18990 if (cy!=ay) { cp = np; cx = nx; cy = ny; }
philpem@5 18991 }
philpem@5 18992 }
philpem@5 18993 for (int y = 0; y<(int)dy; ++y) {
philpem@5 18994 tmp.assign(X.ptr(1,y),X(0,y),1,1,1,true).sort();
philpem@5 18995 for (int i = 1; i<=X(0,y); ) {
philpem@5 18996 const int xb = X(i++,y), xe = X(i++,y);
philpem@5 18997 _draw_scanline(xb,xe,nymin+y,color,opacity);
philpem@5 18998 }
philpem@5 18999 }
philpem@5 19000 return *this;
philpem@5 19001 }
philpem@5 19002
philpem@5 19003 //! Draw a filled polygon in the instance image.
philpem@5 19004 template<typename t, typename tc>
philpem@5 19005 CImg<T>& draw_polygon(const CImgList<t>& points,
philpem@5 19006 const tc *const color, const float opacity=1) {
philpem@5 19007 if (!points.is_sameY(2))
philpem@5 19008 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
philpem@5 19009 pixel_type());
philpem@5 19010 return _draw_polygon(points,points.size,color,opacity);
philpem@5 19011 }
philpem@5 19012
philpem@5 19013 //! Draw a filled polygon in the instance image.
philpem@5 19014 template<typename t, typename tc>
philpem@5 19015 CImg<T>& draw_polygon(const CImgList<t>& points,
philpem@5 19016 const CImg<tc>& color, const float opacity=1) {
philpem@5 19017 return draw_polygon(points,color.data,opacity);
philpem@5 19018 }
philpem@5 19019
philpem@5 19020 //! Draw a filled polygon in the instance image.
philpem@5 19021 template<typename t, typename tc>
philpem@5 19022 CImg<T>& draw_polygon(const CImg<t>& points,
philpem@5 19023 const tc *const color, const float opacity=1) {
philpem@5 19024 if (points.height<2)
philpem@5 19025 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
philpem@5 19026 pixel_type());
philpem@5 19027 return _draw_polygon(points,points.width,color,opacity);
philpem@5 19028 }
philpem@5 19029
philpem@5 19030 //! Draw a filled polygon in the instance image.
philpem@5 19031 template<typename t, typename tc>
philpem@5 19032 CImg<T>& draw_polygon(const CImg<t>& points,
philpem@5 19033 const CImg<tc>& color, const float opacity=1) {
philpem@5 19034 return draw_polygon(points,color.data,opacity);
philpem@5 19035 }
philpem@5 19036
philpem@5 19037 // Inner routine for drawing an outlined polygon with generic point coordinates.
philpem@5 19038 template<typename t, typename tc>
philpem@5 19039 CImg<T>& _draw_polygon(const t& points, const unsigned int W, const unsigned int H,
philpem@5 19040 const tc *const color, const float opacity,
philpem@5 19041 const unsigned int pattern) {
philpem@5 19042 if (is_empty() || !points || W<3) return *this;
philpem@5 19043 bool ninit_hatch = true;
philpem@5 19044 switch (H) {
philpem@5 19045 case 0 : case 1 :
philpem@5 19046 throw CImgArgumentException("CImg<%s>::draw_polygon() : Given list of points is not valid.",
philpem@5 19047 pixel_type());
philpem@5 19048 case 2 : {
philpem@5 19049 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
philpem@5 19050 int ox = x0, oy = y0;
philpem@5 19051 for (unsigned int i = 1; i<W; ++i) {
philpem@5 19052 const int x = (int)points(i,0), y = (int)points(i,1);
philpem@5 19053 draw_line(ox,oy,x,y,color,opacity,pattern,ninit_hatch);
philpem@5 19054 ninit_hatch = false;
philpem@5 19055 ox = x; oy = y;
philpem@5 19056 }
philpem@5 19057 draw_line(ox,oy,x0,y0,color,opacity,pattern,false);
philpem@5 19058 } break;
philpem@5 19059 default : {
philpem@5 19060 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
philpem@5 19061 int ox = x0, oy = y0, oz = z0;
philpem@5 19062 for (unsigned int i = 1; i<W; ++i) {
philpem@5 19063 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
philpem@5 19064 draw_line(ox,oy,oz,x,y,z,color,opacity,pattern,ninit_hatch);
philpem@5 19065 ninit_hatch = false;
philpem@5 19066 ox = x; oy = y; oz = z;
philpem@5 19067 }
philpem@5 19068 draw_line(ox,oy,oz,x0,y0,z0,color,opacity,pattern,false);
philpem@5 19069 }
philpem@5 19070 }
philpem@5 19071 return *this;
philpem@5 19072 }
philpem@5 19073
philpem@5 19074 //! Draw a polygon outline.
philpem@5 19075 template<typename t, typename tc>
philpem@5 19076 CImg<T>& draw_polygon(const CImgList<t>& points,
philpem@5 19077 const tc *const color, const float opacity,
philpem@5 19078 const unsigned int pattern) {
philpem@5 19079 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()));
philpem@5 19080 return _draw_polygon(points,points.size,H,color,opacity,pattern);
philpem@5 19081 }
philpem@5 19082
philpem@5 19083 //! Draw a polygon outline.
philpem@5 19084 template<typename t, typename tc>
philpem@5 19085 CImg<T>& draw_polygon(const CImgList<t>& points,
philpem@5 19086 const CImg<tc>& color, const float opacity,
philpem@5 19087 const unsigned int pattern) {
philpem@5 19088 return draw_polygon(points,color.data,opacity,pattern);
philpem@5 19089 }
philpem@5 19090
philpem@5 19091 //! Draw a polygon outline.
philpem@5 19092 template<typename t, typename tc>
philpem@5 19093 CImg<T>& draw_polygon(const CImg<t>& points,
philpem@5 19094 const tc *const color, const float opacity,
philpem@5 19095 const unsigned int pattern) {
philpem@5 19096 return _draw_polygon(points,points.width,points.height,color,opacity,pattern);
philpem@5 19097 }
philpem@5 19098
philpem@5 19099 //! Draw a polygon outline.
philpem@5 19100 template<typename t, typename tc>
philpem@5 19101 CImg<T>& draw_polygon(const CImg<t>& points,
philpem@5 19102 const CImg<tc>& color, const float opacity,
philpem@5 19103 const unsigned int pattern) {
philpem@5 19104 return draw_polygon(points,color.data,opacity,pattern);
philpem@5 19105 }
philpem@5 19106
philpem@5 19107 //! Draw a cubic spline curve in the instance image.
philpem@5 19108 /**
philpem@5 19109 \param x0 X-coordinate of the starting curve point
philpem@5 19110 \param y0 Y-coordinate of the starting curve point
philpem@5 19111 \param u0 X-coordinate of the starting velocity
philpem@5 19112 \param v0 Y-coordinate of the starting velocity
philpem@5 19113 \param x1 X-coordinate of the ending curve point
philpem@5 19114 \param y1 Y-coordinate of the ending curve point
philpem@5 19115 \param u1 X-coordinate of the ending velocity
philpem@5 19116 \param v1 Y-coordinate of the ending velocity
philpem@5 19117 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 19118 \param precision Curve drawing precision (optional).
philpem@5 19119 \param opacity Drawing opacity (optional).
philpem@5 19120 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 19121 \param init_hatch If \c true, init hatch motif.
philpem@5 19122 \note
philpem@5 19123 - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points
philpem@5 19124 and corresponding velocity vectors.
philpem@5 19125 - The spline is drawn as a serie of connected segments. The \p precision parameter sets the
philpem@5 19126 average number of pixels in each drawn segment.
philpem@5 19127 - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), (\p xb,\p yb), (\p x1,\p y1) }
philpem@5 19128 where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point and (\p xa,\p ya), (\p xb,\p yb) are two
philpem@5 19129 \e control points.
philpem@5 19130 The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from the control points as
philpem@5 19131 \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb).
philpem@5 19132 \par Example:
philpem@5 19133 \code
philpem@5 19134 CImg<unsigned char> img(100,100,1,3,0);
philpem@5 19135 const unsigned char color[] = { 255,255,255 };
philpem@5 19136 img.draw_spline(30,30,0,100,90,40,0,-100,color);
philpem@5 19137 \endcode
philpem@5 19138 **/
philpem@5 19139 template<typename tc>
philpem@5 19140 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
philpem@5 19141 const int x1, const int y1, const float u1, const float v1,
philpem@5 19142 const tc *const color, const float opacity=1,
philpem@5 19143 const float precision=4, const unsigned int pattern=~0U,
philpem@5 19144 const bool init_hatch=true) {
philpem@5 19145 if (is_empty()) return *this;
philpem@5 19146 if (!color)
philpem@5 19147 throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
philpem@5 19148 pixel_type());
philpem@5 19149 bool ninit_hatch = init_hatch;
philpem@5 19150 const float
philpem@5 19151 dx = (float)(x1 - x0),
philpem@5 19152 dy = (float)(y1 - y0),
philpem@5 19153 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
philpem@5 19154 ax = -2*dx + u0 + u1,
philpem@5 19155 bx = 3*dx - 2*u0 - u1,
philpem@5 19156 ay = -2*dy + v0 + v1,
philpem@5 19157 by = 3*dy - 2*v0 - v1,
philpem@5 19158 xprecision = dmax>0?precision/dmax:1.0f,
philpem@5 19159 tmax = 1 + (dmax>0?xprecision:0.0f);
philpem@5 19160 int ox = x0, oy = y0;
philpem@5 19161 for (float t = 0; t<tmax; t+=xprecision) {
philpem@5 19162 const float
philpem@5 19163 t2 = t*t,
philpem@5 19164 t3 = t2*t;
philpem@5 19165 const int
philpem@5 19166 nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
philpem@5 19167 ny = (int)(ay*t3 + by*t2 + v0*t + y0);
philpem@5 19168 draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch);
philpem@5 19169 ninit_hatch = false;
philpem@5 19170 ox = nx; oy = ny;
philpem@5 19171 }
philpem@5 19172 return *this;
philpem@5 19173 }
philpem@5 19174
philpem@5 19175 //! Draw a cubic spline curve in the instance image.
philpem@5 19176 template<typename tc>
philpem@5 19177 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
philpem@5 19178 const int x1, const int y1, const float u1, const float v1,
philpem@5 19179 const CImg<tc>& color, const float opacity=1,
philpem@5 19180 const float precision=4, const unsigned int pattern=~0U,
philpem@5 19181 const bool init_hatch=true) {
philpem@5 19182 return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,color.data,opacity,precision,pattern,init_hatch);
philpem@5 19183 }
philpem@5 19184
philpem@5 19185 //! Draw a cubic spline curve in the instance image (for volumetric images).
philpem@5 19186 /**
philpem@5 19187 \note
philpem@5 19188 - Similar to CImg::draw_spline() for a 3D spline in a volumetric image.
philpem@5 19189 **/
philpem@5 19190 template<typename tc>
philpem@5 19191 CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
philpem@5 19192 const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
philpem@5 19193 const tc *const color, const float opacity=1,
philpem@5 19194 const float precision=4, const unsigned int pattern=~0U,
philpem@5 19195 const bool init_hatch=true) {
philpem@5 19196 if (is_empty()) return *this;
philpem@5 19197 if (!color)
philpem@5 19198 throw CImgArgumentException("CImg<%s>::draw_spline() : Specified color is (null)",
philpem@5 19199 pixel_type());
philpem@5 19200 bool ninit_hatch = init_hatch;
philpem@5 19201 const float
philpem@5 19202 dx = (float)(x1 - x0),
philpem@5 19203 dy = (float)(y1 - y0),
philpem@5 19204 dz = (float)(z1 - z0),
philpem@5 19205 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy),cimg::abs(dz)),
philpem@5 19206 ax = -2*dx + u0 + u1,
philpem@5 19207 bx = 3*dx - 2*u0 - u1,
philpem@5 19208 ay = -2*dy + v0 + v1,
philpem@5 19209 by = 3*dy - 2*v0 - v1,
philpem@5 19210 az = -2*dz + w0 + w1,
philpem@5 19211 bz = 3*dz - 2*w0 - w1,
philpem@5 19212 xprecision = dmax>0?precision/dmax:1.0f,
philpem@5 19213 tmax = 1 + (dmax>0?xprecision:0.0f);
philpem@5 19214 int ox = x0, oy = y0, oz = z0;
philpem@5 19215 for (float t = 0; t<tmax; t+=xprecision) {
philpem@5 19216 const float
philpem@5 19217 t2 = t*t,
philpem@5 19218 t3 = t2*t;
philpem@5 19219 const int
philpem@5 19220 nx = (int)(ax*t3 + bx*t2 + u0*t + x0),
philpem@5 19221 ny = (int)(ay*t3 + by*t2 + v0*t + y0),
philpem@5 19222 nz = (int)(az*t3 + bz*t2 + w0*t + z0);
philpem@5 19223 draw_line(ox,oy,oz,nx,ny,nz,color,opacity,pattern,ninit_hatch);
philpem@5 19224 ninit_hatch = false;
philpem@5 19225 ox = nx; oy = ny; oz = nz;
philpem@5 19226 }
philpem@5 19227 return *this;
philpem@5 19228 }
philpem@5 19229
philpem@5 19230 //! Draw a cubic spline curve in the instance image (for volumetric images).
philpem@5 19231 template<typename tc>
philpem@5 19232 CImg<T>& draw_spline(const int x0, const int y0, const int z0, const float u0, const float v0, const float w0,
philpem@5 19233 const int x1, const int y1, const int z1, const float u1, const float v1, const float w1,
philpem@5 19234 const CImg<tc>& color, const float opacity=1,
philpem@5 19235 const float precision=4, const unsigned int pattern=~0U,
philpem@5 19236 const bool init_hatch=true) {
philpem@5 19237 return draw_spline(x0,y0,z0,u0,v0,w0,x1,y1,z1,u1,v1,w1,color.data,opacity,precision,pattern,init_hatch);
philpem@5 19238 }
philpem@5 19239
philpem@5 19240 //! Draw a cubic spline curve in the instance image.
philpem@5 19241 /**
philpem@5 19242 \param x0 X-coordinate of the starting curve point
philpem@5 19243 \param y0 Y-coordinate of the starting curve point
philpem@5 19244 \param u0 X-coordinate of the starting velocity
philpem@5 19245 \param v0 Y-coordinate of the starting velocity
philpem@5 19246 \param x1 X-coordinate of the ending curve point
philpem@5 19247 \param y1 Y-coordinate of the ending curve point
philpem@5 19248 \param u1 X-coordinate of the ending velocity
philpem@5 19249 \param v1 Y-coordinate of the ending velocity
philpem@5 19250 \param texture Texture image defining line pixel colors.
philpem@5 19251 \param tx0 X-coordinate of the starting texture point.
philpem@5 19252 \param ty0 Y-coordinate of the starting texture point.
philpem@5 19253 \param tx1 X-coordinate of the ending texture point.
philpem@5 19254 \param ty1 Y-coordinate of the ending texture point.
philpem@5 19255 \param precision Curve drawing precision (optional).
philpem@5 19256 \param opacity Drawing opacity (optional).
philpem@5 19257 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 19258 \param init_hatch if \c true, reinit hatch motif.
philpem@5 19259 **/
philpem@5 19260 template<typename t>
philpem@5 19261 CImg<T>& draw_spline(const int x0, const int y0, const float u0, const float v0,
philpem@5 19262 const int x1, const int y1, const float u1, const float v1,
philpem@5 19263 const CImg<t>& texture,
philpem@5 19264 const int tx0, const int ty0, const int tx1, const int ty1,
philpem@5 19265 const float opacity=1,
philpem@5 19266 const float precision=4, const unsigned int pattern=~0U,
philpem@5 19267 const bool init_hatch=true) {
philpem@5 19268 if (is_empty()) return *this;
philpem@5 19269 if (!texture || texture.dim<dim)
philpem@5 19270 throw CImgArgumentException("CImg<%s>::draw_line() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 19271 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 19272 if (is_overlapped(texture)) return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch);
philpem@5 19273 bool ninit_hatch = true;
philpem@5 19274 const float
philpem@5 19275 dx = (float)(x1 - x0),
philpem@5 19276 dy = (float)(y1 - y0),
philpem@5 19277 dmax = cimg::max(cimg::abs(dx),cimg::abs(dy)),
philpem@5 19278 ax = -2*dx + u0 + u1,
philpem@5 19279 bx = 3*dx - 2*u0 - u1,
philpem@5 19280 ay = -2*dy + v0 + v1,
philpem@5 19281 by = 3*dy - 2*v0 - v1,
philpem@5 19282 xprecision = dmax>0?precision/dmax:1.0f,
philpem@5 19283 tmax = 1 + (dmax>0?xprecision:0.0f);
philpem@5 19284 int ox = x0, oy = y0, otx = tx0, oty = ty0;
philpem@5 19285 for (float t1 = 0; t1<tmax; t1+=xprecision) {
philpem@5 19286 const float
philpem@5 19287 t2 = t1*t1,
philpem@5 19288 t3 = t2*t1;
philpem@5 19289 const int
philpem@5 19290 nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0),
philpem@5 19291 ny = (int)(ay*t3 + by*t2 + v0*t1 + y0),
philpem@5 19292 ntx = tx0 + (int)((tx1-tx0)*t1/tmax),
philpem@5 19293 nty = ty0 + (int)((ty1-ty0)*t1/tmax);
philpem@5 19294 draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch);
philpem@5 19295 ninit_hatch = false;
philpem@5 19296 ox = nx; oy = ny; otx = ntx; oty = nty;
philpem@5 19297 }
philpem@5 19298 return *this;
philpem@5 19299 }
philpem@5 19300
philpem@5 19301 // Draw a set of connected spline curves in the instance image (internal).
philpem@5 19302 template<typename tp, typename tt, typename tc>
philpem@5 19303 CImg<T>& _draw_spline(const tp& points, const tt& tangents, const unsigned int W, const unsigned int H,
philpem@5 19304 const tc *const color, const float opacity,
philpem@5 19305 const bool close_set, const float precision,
philpem@5 19306 const unsigned int pattern, const bool init_hatch) {
philpem@5 19307 if (is_empty() || !points || !tangents || W<2) return *this;
philpem@5 19308 bool ninit_hatch = init_hatch;
philpem@5 19309 switch (H) {
philpem@5 19310 case 0 : case 1 :
philpem@5 19311 throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
philpem@5 19312 pixel_type());
philpem@5 19313 case 2 : {
philpem@5 19314 const int x0 = (int)points(0,0), y0 = (int)points(0,1);
philpem@5 19315 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1);
philpem@5 19316 int ox = x0, oy = y0;
philpem@5 19317 float ou = u0, ov = v0;
philpem@5 19318 for (unsigned int i = 1; i<W; ++i) {
philpem@5 19319 const int x = (int)points(i,0), y = (int)points(i,1);
philpem@5 19320 const float u = (float)tangents(i,0), v = (float)tangents(i,1);
philpem@5 19321 draw_spline(ox,oy,ou,ov,x,y,u,v,color,precision,opacity,pattern,ninit_hatch);
philpem@5 19322 ninit_hatch = false;
philpem@5 19323 ox = x; oy = y; ou = u; ov = v;
philpem@5 19324 }
philpem@5 19325 if (close_set) draw_spline(ox,oy,ou,ov,x0,y0,u0,v0,color,precision,opacity,pattern,false);
philpem@5 19326 } break;
philpem@5 19327 default : {
philpem@5 19328 const int x0 = (int)points(0,0), y0 = (int)points(0,1), z0 = (int)points(0,2);
philpem@5 19329 const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1), w0 = (float)tangents(0,2);
philpem@5 19330 int ox = x0, oy = y0, oz = z0;
philpem@5 19331 float ou = u0, ov = v0, ow = w0;
philpem@5 19332 for (unsigned int i = 1; i<W; ++i) {
philpem@5 19333 const int x = (int)points(i,0), y = (int)points(i,1), z = (int)points(i,2);
philpem@5 19334 const float u = (float)tangents(i,0), v = (float)tangents(i,1), w = (float)tangents(i,2);
philpem@5 19335 draw_spline(ox,oy,oz,ou,ov,ow,x,y,z,u,v,w,color,opacity,pattern,ninit_hatch);
philpem@5 19336 ninit_hatch = false;
philpem@5 19337 ox = x; oy = y; oz = z; ou = u; ov = v; ow = w;
philpem@5 19338 }
philpem@5 19339 if (close_set) draw_spline(ox,oy,oz,ou,ov,ow,x0,y0,z0,u0,v0,w0,color,precision,opacity,pattern,false);
philpem@5 19340 }
philpem@5 19341 }
philpem@5 19342 return *this;
philpem@5 19343 }
philpem@5 19344
philpem@5 19345 // Draw a set of connected spline curves in the instance image (internal).
philpem@5 19346 template<typename tp, typename tc>
philpem@5 19347 CImg<T>& _draw_spline(const tp& points, const unsigned int W, const unsigned int H,
philpem@5 19348 const tc *const color, const float opacity,
philpem@5 19349 const bool close_set, const float precision,
philpem@5 19350 const unsigned int pattern, const bool init_hatch) {
philpem@5 19351 if (is_empty() || !points || W<2) return *this;
philpem@5 19352 CImg<Tfloat> tangents;
philpem@5 19353 switch (H) {
philpem@5 19354 case 0 : case 1 :
philpem@5 19355 throw CImgArgumentException("CImg<%s>::draw_spline() : Given list of points or tangents is not valid.",
philpem@5 19356 pixel_type());
philpem@5 19357 case 2 : {
philpem@5 19358 tangents.assign(W,H);
philpem@5 19359 for (unsigned int p = 0; p<W; ++p) {
philpem@5 19360 const unsigned int
philpem@5 19361 p0 = close_set?(p+W-1)%W:(p?p-1:0),
philpem@5 19362 p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
philpem@5 19363 const float
philpem@5 19364 x = (float)points(p,0),
philpem@5 19365 y = (float)points(p,1),
philpem@5 19366 x0 = (float)points(p0,0),
philpem@5 19367 y0 = (float)points(p0,1),
philpem@5 19368 x1 = (float)points(p1,0),
philpem@5 19369 y1 = (float)points(p1,1),
philpem@5 19370 u0 = x - x0,
philpem@5 19371 v0 = y - y0,
philpem@5 19372 n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0),
philpem@5 19373 u1 = x1 - x,
philpem@5 19374 v1 = y1 - y,
philpem@5 19375 n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1),
philpem@5 19376 u = u0/n0 + u1/n1,
philpem@5 19377 v = v0/n0 + v1/n1,
philpem@5 19378 n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v),
philpem@5 19379 fact = 0.5f*(n0 + n1);
philpem@5 19380 tangents(p,0) = (Tfloat)(fact*u/n);
philpem@5 19381 tangents(p,1) = (Tfloat)(fact*v/n);
philpem@5 19382 }
philpem@5 19383 } break;
philpem@5 19384 default : {
philpem@5 19385 tangents.assign(W,H);
philpem@5 19386 for (unsigned int p = 0; p<W; ++p) {
philpem@5 19387 const unsigned int
philpem@5 19388 p0 = close_set?(p+W-1)%W:(p?p-1:0),
philpem@5 19389 p1 = close_set?(p+1)%W:(p+1<W?p+1:p);
philpem@5 19390 const float
philpem@5 19391 x = (float)points(p,0),
philpem@5 19392 y = (float)points(p,1),
philpem@5 19393 z = (float)points(p,2),
philpem@5 19394 x0 = (float)points(p0,0),
philpem@5 19395 y0 = (float)points(p0,1),
philpem@5 19396 z0 = (float)points(p0,2),
philpem@5 19397 x1 = (float)points(p1,0),
philpem@5 19398 y1 = (float)points(p1,1),
philpem@5 19399 z1 = (float)points(p1,2),
philpem@5 19400 u0 = x - x0,
philpem@5 19401 v0 = y - y0,
philpem@5 19402 w0 = z - z0,
philpem@5 19403 n0 = 1e-8f + (float)cimg_std::sqrt(u0*u0 + v0*v0 + w0*w0),
philpem@5 19404 u1 = x1 - x,
philpem@5 19405 v1 = y1 - y,
philpem@5 19406 w1 = z1 - z,
philpem@5 19407 n1 = 1e-8f + (float)cimg_std::sqrt(u1*u1 + v1*v1 + w1*w1),
philpem@5 19408 u = u0/n0 + u1/n1,
philpem@5 19409 v = v0/n0 + v1/n1,
philpem@5 19410 w = w0/n0 + w1/n1,
philpem@5 19411 n = 1e-8f + (float)cimg_std::sqrt(u*u + v*v + w*w),
philpem@5 19412 fact = 0.5f*(n0 + n1);
philpem@5 19413 tangents(p,0) = (Tfloat)(fact*u/n);
philpem@5 19414 tangents(p,1) = (Tfloat)(fact*v/n);
philpem@5 19415 tangents(p,2) = (Tfloat)(fact*w/n);
philpem@5 19416 }
philpem@5 19417 }
philpem@5 19418 }
philpem@5 19419 return _draw_spline(points,tangents,W,H,color,opacity,close_set,precision,pattern,init_hatch);
philpem@5 19420 }
philpem@5 19421
philpem@5 19422 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19423 template<typename tp, typename tt, typename tc>
philpem@5 19424 CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
philpem@5 19425 const tc *const color, const float opacity=1,
philpem@5 19426 const bool close_set=false, const float precision=4,
philpem@5 19427 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19428 unsigned int H = ~0U; cimglist_for(points,p) H = cimg::min(H,(unsigned int)(points[p].size()),(unsigned int)(tangents[p].size()));
philpem@5 19429 return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
philpem@5 19430 }
philpem@5 19431
philpem@5 19432 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19433 template<typename tp, typename tt, typename tc>
philpem@5 19434 CImg<T>& draw_spline(const CImgList<tp>& points, const CImgList<tt>& tangents,
philpem@5 19435 const CImg<tc>& color, const float opacity=1,
philpem@5 19436 const bool close_set=false, const float precision=4,
philpem@5 19437 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19438 return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
philpem@5 19439 }
philpem@5 19440
philpem@5 19441 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19442 template<typename tp, typename tt, typename tc>
philpem@5 19443 CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
philpem@5 19444 const tc *const color, const float opacity=1,
philpem@5 19445 const bool close_set=false, const float precision=4,
philpem@5 19446 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19447 return _draw_spline(points,tangents,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
philpem@5 19448 }
philpem@5 19449
philpem@5 19450 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19451 template<typename tp, typename tt, typename tc>
philpem@5 19452 CImg<T>& draw_spline(const CImg<tp>& points, const CImg<tt>& tangents,
philpem@5 19453 const CImg<tc>& color, const float opacity=1,
philpem@5 19454 const bool close_set=false, const float precision=4,
philpem@5 19455 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19456 return draw_spline(points,tangents,color.data,opacity,close_set,precision,pattern,init_hatch);
philpem@5 19457 }
philpem@5 19458
philpem@5 19459 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19460 template<typename t, typename tc>
philpem@5 19461 CImg<T>& draw_spline(const CImgList<t>& points,
philpem@5 19462 const tc *const color, const float opacity=1,
philpem@5 19463 const bool close_set=false, const float precision=4,
philpem@5 19464 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19465 unsigned int H = ~0U;
philpem@5 19466 cimglist_for(points,p) { const unsigned int s = points[p].size(); if (s<H) H = s; }
philpem@5 19467 return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.size,H);
philpem@5 19468 }
philpem@5 19469
philpem@5 19470 //! Draw a set of consecutive colored splines in the instance image.
philpem@5 19471 template<typename t, typename tc>
philpem@5 19472 CImg<T>& draw_spline(const CImgList<t>& points,
philpem@5 19473 CImg<tc>& color, const float opacity=1,
philpem@5 19474 const bool close_set=false, const float precision=4,
philpem@5 19475 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19476 return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
philpem@5 19477 }
philpem@5 19478
philpem@5 19479 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 19480 template<typename t, typename tc>
philpem@5 19481 CImg<T>& draw_spline(const CImg<t>& points,
philpem@5 19482 const tc *const color, const float opacity=1,
philpem@5 19483 const bool close_set=false, const float precision=4,
philpem@5 19484 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19485 return _draw_spline(points,color,opacity,close_set,precision,pattern,init_hatch,points.width,points.height);
philpem@5 19486 }
philpem@5 19487
philpem@5 19488 //! Draw a set of consecutive colored lines in the instance image.
philpem@5 19489 template<typename t, typename tc>
philpem@5 19490 CImg<T>& draw_spline(const CImg<t>& points,
philpem@5 19491 const CImg<tc>& color, const float opacity=1,
philpem@5 19492 const bool close_set=false, const float precision=4,
philpem@5 19493 const unsigned int pattern=~0U, const bool init_hatch=true) {
philpem@5 19494 return draw_spline(points,color.data,opacity,close_set,precision,pattern,init_hatch);
philpem@5 19495 }
philpem@5 19496
philpem@5 19497 //! Draw a colored arrow in the instance image.
philpem@5 19498 /**
philpem@5 19499 \param x0 X-coordinate of the starting arrow point (tail).
philpem@5 19500 \param y0 Y-coordinate of the starting arrow point (tail).
philpem@5 19501 \param x1 X-coordinate of the ending arrow point (head).
philpem@5 19502 \param y1 Y-coordinate of the ending arrow point (head).
philpem@5 19503 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 19504 \param angle Aperture angle of the arrow head (optional).
philpem@5 19505 \param length Length of the arrow head. If negative, describes a percentage of the arrow length (optional).
philpem@5 19506 \param opacity Drawing opacity (optional).
philpem@5 19507 \param pattern An integer whose bits describe the line pattern (optional).
philpem@5 19508 \note
philpem@5 19509 - Clipping is supported.
philpem@5 19510 **/
philpem@5 19511 template<typename tc>
philpem@5 19512 CImg<T>& draw_arrow(const int x0, const int y0,
philpem@5 19513 const int x1, const int y1,
philpem@5 19514 const tc *const color, const float opacity=1,
philpem@5 19515 const float angle=30, const float length=-10,
philpem@5 19516 const unsigned int pattern=~0U) {
philpem@5 19517 if (is_empty()) return *this;
philpem@5 19518 const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v,
philpem@5 19519 deg = (float)(angle*cimg::valuePI/180), ang = (sq>0)?(float)cimg_std::atan2(v,u):0.0f,
philpem@5 19520 l = (length>=0)?length:-length*(float)cimg_std::sqrt(sq)/100;
philpem@5 19521 if (sq>0) {
philpem@5 19522 const float
philpem@5 19523 cl = (float)cimg_std::cos(ang - deg), sl = (float)cimg_std::sin(ang - deg),
philpem@5 19524 cr = (float)cimg_std::cos(ang + deg), sr = (float)cimg_std::sin(ang + deg);
philpem@5 19525 const int
philpem@5 19526 xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl),
philpem@5 19527 xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr),
philpem@5 19528 xc = x1 + (int)((l+1)*(cl+cr))/2, yc = y1 + (int)((l+1)*(sl+sr))/2;
philpem@5 19529 draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity);
philpem@5 19530 } else draw_point(x0,y0,color,opacity);
philpem@5 19531 return *this;
philpem@5 19532 }
philpem@5 19533
philpem@5 19534 //! Draw a colored arrow in the instance image.
philpem@5 19535 template<typename tc>
philpem@5 19536 CImg<T>& draw_arrow(const int x0, const int y0,
philpem@5 19537 const int x1, const int y1,
philpem@5 19538 const CImg<tc>& color, const float opacity=1,
philpem@5 19539 const float angle=30, const float length=-10,
philpem@5 19540 const unsigned int pattern=~0U) {
philpem@5 19541 return draw_arrow(x0,y0,x1,y1,color.data,opacity,angle,length,pattern);
philpem@5 19542 }
philpem@5 19543
philpem@5 19544 //! Draw an image.
philpem@5 19545 /**
philpem@5 19546 \param sprite Sprite image.
philpem@5 19547 \param x0 X-coordinate of the sprite position.
philpem@5 19548 \param y0 Y-coordinate of the sprite position.
philpem@5 19549 \param z0 Z-coordinate of the sprite position.
philpem@5 19550 \param v0 V-coordinate of the sprite position.
philpem@5 19551 \param opacity Drawing opacity (optional).
philpem@5 19552 \note
philpem@5 19553 - Clipping is supported.
philpem@5 19554 **/
philpem@5 19555 template<typename t>
philpem@5 19556 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
philpem@5 19557 const CImg<t>& sprite, const float opacity=1) {
philpem@5 19558 if (is_empty()) return *this;
philpem@5 19559 if (!sprite)
philpem@5 19560 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
philpem@5 19561 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
philpem@5 19562 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
philpem@5 19563 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
philpem@5 19564 const int
philpem@5 19565 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
philpem@5 19566 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
philpem@5 19567 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
philpem@5 19568 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
philpem@5 19569 const t
philpem@5 19570 *ptrs = sprite.data -
philpem@5 19571 (bx?x0:0) -
philpem@5 19572 (by?y0*sprite.dimx():0) -
philpem@5 19573 (bz?z0*sprite.dimx()*sprite.dimy():0) -
philpem@5 19574 (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
philpem@5 19575 const unsigned int
philpem@5 19576 offX = width - lX, soffX = sprite.width - lX,
philpem@5 19577 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
philpem@5 19578 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
philpem@5 19579 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 19580 if (lX>0 && lY>0 && lZ>0 && lV>0) {
philpem@5 19581 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
philpem@5 19582 for (int v = 0; v<lV; ++v) {
philpem@5 19583 for (int z = 0; z<lZ; ++z) {
philpem@5 19584 for (int y = 0; y<lY; ++y) {
philpem@5 19585 if (opacity>=1) for (int x = 0; x<lX; ++x) *(ptrd++) = (T)*(ptrs++);
philpem@5 19586 else for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
philpem@5 19587 ptrd+=offX; ptrs+=soffX;
philpem@5 19588 }
philpem@5 19589 ptrd+=offY; ptrs+=soffY;
philpem@5 19590 }
philpem@5 19591 ptrd+=offZ; ptrs+=soffZ;
philpem@5 19592 }
philpem@5 19593 }
philpem@5 19594 return *this;
philpem@5 19595 }
philpem@5 19596
philpem@5 19597 #ifndef cimg_use_visualcpp6
philpem@5 19598 // Otimized version (internal).
philpem@5 19599 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
philpem@5 19600 const CImg<T>& sprite, const float opacity=1) {
philpem@5 19601 if (is_empty()) return *this;
philpem@5 19602 if (!sprite)
philpem@5 19603 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
philpem@5 19604 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
philpem@5 19605 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,opacity);
philpem@5 19606 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
philpem@5 19607 const int
philpem@5 19608 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
philpem@5 19609 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
philpem@5 19610 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
philpem@5 19611 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
philpem@5 19612 const T
philpem@5 19613 *ptrs = sprite.data -
philpem@5 19614 (bx?x0:0) -
philpem@5 19615 (by?y0*sprite.dimx():0) -
philpem@5 19616 (bz?z0*sprite.dimx()*sprite.dimy():0) -
philpem@5 19617 (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0);
philpem@5 19618 const unsigned int
philpem@5 19619 offX = width - lX, soffX = sprite.width - lX,
philpem@5 19620 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
philpem@5 19621 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ),
philpem@5 19622 slX = lX*sizeof(T);
philpem@5 19623 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 19624 if (lX>0 && lY>0 && lZ>0 && lV>0) {
philpem@5 19625 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
philpem@5 19626 for (int v = 0; v<lV; ++v) {
philpem@5 19627 for (int z = 0; z<lZ; ++z) {
philpem@5 19628 if (opacity>=1) for (int y = 0; y<lY; ++y) { cimg_std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; }
philpem@5 19629 else for (int y = 0; y<lY; ++y) {
philpem@5 19630 for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*(*(ptrs++)) + *ptrd*copacity); ++ptrd; }
philpem@5 19631 ptrd+=offX; ptrs+=soffX;
philpem@5 19632 }
philpem@5 19633 ptrd+=offY; ptrs+=soffY;
philpem@5 19634 }
philpem@5 19635 ptrd+=offZ; ptrs+=soffZ;
philpem@5 19636 }
philpem@5 19637 }
philpem@5 19638 return *this;
philpem@5 19639 }
philpem@5 19640 #endif
philpem@5 19641
philpem@5 19642 //! Draw an image.
philpem@5 19643 template<typename t>
philpem@5 19644 CImg<T>& draw_image(const int x0, const int y0, const int z0,
philpem@5 19645 const CImg<t>& sprite, const float opacity=1) {
philpem@5 19646 return draw_image(x0,y0,z0,0,sprite,opacity);
philpem@5 19647 }
philpem@5 19648
philpem@5 19649 //! Draw an image.
philpem@5 19650 template<typename t>
philpem@5 19651 CImg<T>& draw_image(const int x0, const int y0,
philpem@5 19652 const CImg<t>& sprite, const float opacity=1) {
philpem@5 19653 return draw_image(x0,y0,0,sprite,opacity);
philpem@5 19654 }
philpem@5 19655
philpem@5 19656 //! Draw an image.
philpem@5 19657 template<typename t>
philpem@5 19658 CImg<T>& draw_image(const int x0,
philpem@5 19659 const CImg<t>& sprite, const float opacity=1) {
philpem@5 19660 return draw_image(x0,0,sprite,opacity);
philpem@5 19661 }
philpem@5 19662
philpem@5 19663 //! Draw an image.
philpem@5 19664 template<typename t>
philpem@5 19665 CImg<T>& draw_image(const CImg<t>& sprite, const float opacity=1) {
philpem@5 19666 return draw_image(0,sprite,opacity);
philpem@5 19667 }
philpem@5 19668
philpem@5 19669 //! Draw a sprite image in the instance image (masked version).
philpem@5 19670 /**
philpem@5 19671 \param sprite Sprite image.
philpem@5 19672 \param mask Mask image.
philpem@5 19673 \param x0 X-coordinate of the sprite position in the instance image.
philpem@5 19674 \param y0 Y-coordinate of the sprite position in the instance image.
philpem@5 19675 \param z0 Z-coordinate of the sprite position in the instance image.
philpem@5 19676 \param v0 V-coordinate of the sprite position in the instance image.
philpem@5 19677 \param mask_valmax Maximum pixel value of the mask image \c mask (optional).
philpem@5 19678 \param opacity Drawing opacity.
philpem@5 19679 \note
philpem@5 19680 - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite.
philpem@5 19681 - Clipping is supported.
philpem@5 19682 - Dimensions along x,y and z of \p sprite and \p mask must be the same.
philpem@5 19683 **/
philpem@5 19684 template<typename ti, typename tm>
philpem@5 19685 CImg<T>& draw_image(const int x0, const int y0, const int z0, const int v0,
philpem@5 19686 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
philpem@5 19687 const float mask_valmax=1) {
philpem@5 19688 if (is_empty()) return *this;
philpem@5 19689 if (!sprite)
philpem@5 19690 throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.",
philpem@5 19691 pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data);
philpem@5 19692 if (!mask)
philpem@5 19693 throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.",
philpem@5 19694 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
philpem@5 19695 if (is_overlapped(sprite)) return draw_image(x0,y0,z0,v0,+sprite,mask,opacity,mask_valmax);
philpem@5 19696 if (is_overlapped(mask)) return draw_image(x0,y0,z0,v0,sprite,+mask,opacity,mask_valmax);
philpem@5 19697 if (mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth)
philpem@5 19698 throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)",
philpem@5 19699 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim);
philpem@5 19700 const bool bx = (x0<0), by = (y0<0), bz = (z0<0), bv = (v0<0);
philpem@5 19701 const int
philpem@5 19702 lX = sprite.dimx() - (x0 + sprite.dimx()>dimx()?x0 + sprite.dimx() - dimx():0) + (bx?x0:0),
philpem@5 19703 lY = sprite.dimy() - (y0 + sprite.dimy()>dimy()?y0 + sprite.dimy() - dimy():0) + (by?y0:0),
philpem@5 19704 lZ = sprite.dimz() - (z0 + sprite.dimz()>dimz()?z0 + sprite.dimz() - dimz():0) + (bz?z0:0),
philpem@5 19705 lV = sprite.dimv() - (v0 + sprite.dimv()>dimv()?v0 + sprite.dimv() - dimv():0) + (bv?v0:0);
philpem@5 19706 const int
philpem@5 19707 coff = -(bx?x0:0)-(by?y0*mask.dimx():0)-(bz?z0*mask.dimx()*mask.dimy():0)-(bv?v0*mask.dimx()*mask.dimy()*mask.dimz():0),
philpem@5 19708 ssize = mask.dimx()*mask.dimy()*mask.dimz();
philpem@5 19709 const ti *ptrs = sprite.data + coff;
philpem@5 19710 const tm *ptrm = mask.data + coff;
philpem@5 19711 const unsigned int
philpem@5 19712 offX = width - lX, soffX = sprite.width - lX,
philpem@5 19713 offY = width*(height - lY), soffY = sprite.width*(sprite.height - lY),
philpem@5 19714 offZ = width*height*(depth - lZ), soffZ = sprite.width*sprite.height*(sprite.depth - lZ);
philpem@5 19715 if (lX>0 && lY>0 && lZ>0 && lV>0) {
philpem@5 19716 T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0);
philpem@5 19717 for (int v = 0; v<lV; ++v) {
philpem@5 19718 ptrm = mask.data + (ptrm - mask.data)%ssize;
philpem@5 19719 for (int z = 0; z<lZ; ++z) {
philpem@5 19720 for (int y = 0; y<lY; ++y) {
philpem@5 19721 for (int x=0; x<lX; ++x) {
philpem@5 19722 const float mopacity = (float)(*(ptrm++)*opacity),
philpem@5 19723 nopacity = cimg::abs(mopacity), copacity = mask_valmax - cimg::max(mopacity,0);
philpem@5 19724 *ptrd = (T)((nopacity*(*(ptrs++)) + *ptrd*copacity)/mask_valmax);
philpem@5 19725 ++ptrd;
philpem@5 19726 }
philpem@5 19727 ptrd+=offX; ptrs+=soffX; ptrm+=soffX;
philpem@5 19728 }
philpem@5 19729 ptrd+=offY; ptrs+=soffY; ptrm+=soffY;
philpem@5 19730 }
philpem@5 19731 ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ;
philpem@5 19732 }
philpem@5 19733 }
philpem@5 19734 return *this;
philpem@5 19735 }
philpem@5 19736
philpem@5 19737 //! Draw an image.
philpem@5 19738 template<typename ti, typename tm>
philpem@5 19739 CImg<T>& draw_image(const int x0, const int y0, const int z0,
philpem@5 19740 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
philpem@5 19741 const float mask_valmax=1) {
philpem@5 19742 return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_valmax);
philpem@5 19743 }
philpem@5 19744
philpem@5 19745 //! Draw an image.
philpem@5 19746 template<typename ti, typename tm>
philpem@5 19747 CImg<T>& draw_image(const int x0, const int y0,
philpem@5 19748 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
philpem@5 19749 const float mask_valmax=1) {
philpem@5 19750 return draw_image(x0,y0,0,sprite,mask,opacity,mask_valmax);
philpem@5 19751 }
philpem@5 19752
philpem@5 19753 //! Draw an image.
philpem@5 19754 template<typename ti, typename tm>
philpem@5 19755 CImg<T>& draw_image(const int x0,
philpem@5 19756 const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
philpem@5 19757 const float mask_valmax=1) {
philpem@5 19758 return draw_image(x0,0,sprite,mask,opacity,mask_valmax);
philpem@5 19759 }
philpem@5 19760
philpem@5 19761 //! Draw an image.
philpem@5 19762 template<typename ti, typename tm>
philpem@5 19763 CImg<T>& draw_image(const CImg<ti>& sprite, const CImg<tm>& mask, const float opacity=1,
philpem@5 19764 const float mask_valmax=1) {
philpem@5 19765 return draw_image(0,sprite,mask,opacity,mask_valmax);
philpem@5 19766 }
philpem@5 19767
philpem@5 19768 //! Draw a 4D filled rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0)-(\c x1,\c y1,\c z1,\c v1).
philpem@5 19769 /**
philpem@5 19770 \param x0 X-coordinate of the upper-left rectangle corner.
philpem@5 19771 \param y0 Y-coordinate of the upper-left rectangle corner.
philpem@5 19772 \param z0 Z-coordinate of the upper-left rectangle corner.
philpem@5 19773 \param v0 V-coordinate of the upper-left rectangle corner.
philpem@5 19774 \param x1 X-coordinate of the lower-right rectangle corner.
philpem@5 19775 \param y1 Y-coordinate of the lower-right rectangle corner.
philpem@5 19776 \param z1 Z-coordinate of the lower-right rectangle corner.
philpem@5 19777 \param v1 V-coordinate of the lower-right rectangle corner.
philpem@5 19778 \param val Scalar value used to fill the rectangle area.
philpem@5 19779 \param opacity Drawing opacity (optional).
philpem@5 19780 \note
philpem@5 19781 - Clipping is supported.
philpem@5 19782 **/
philpem@5 19783 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0, const int v0,
philpem@5 19784 const int x1, const int y1, const int z1, const int v1,
philpem@5 19785 const T val, const float opacity=1) {
philpem@5 19786 if (is_empty()) return *this;
philpem@5 19787 const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bv = (v0<v1);
philpem@5 19788 const int
philpem@5 19789 nx0 = bx?x0:x1, nx1 = bx?x1:x0,
philpem@5 19790 ny0 = by?y0:y1, ny1 = by?y1:y0,
philpem@5 19791 nz0 = bz?z0:z1, nz1 = bz?z1:z0,
philpem@5 19792 nv0 = bv?v0:v1, nv1 = bv?v1:v0;
philpem@5 19793 const int
philpem@5 19794 lX = (1 + nx1 - nx0) + (nx1>=dimx()?dimx() - 1 - nx1:0) + (nx0<0?nx0:0),
philpem@5 19795 lY = (1 + ny1 - ny0) + (ny1>=dimy()?dimy() - 1 - ny1:0) + (ny0<0?ny0:0),
philpem@5 19796 lZ = (1 + nz1 - nz0) + (nz1>=dimz()?dimz() - 1 - nz1:0) + (nz0<0?nz0:0),
philpem@5 19797 lV = (1 + nv1 - nv0) + (nv1>=dimv()?dimv() - 1 - nv1:0) + (nv0<0?nv0:0);
philpem@5 19798 const unsigned int offX = width - lX, offY = width*(height - lY), offZ = width*height*(depth - lZ);
philpem@5 19799 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 19800 T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0);
philpem@5 19801 if (lX>0 && lY>0 && lZ>0 && lV>0)
philpem@5 19802 for (int v = 0; v<lV; ++v) {
philpem@5 19803 for (int z = 0; z<lZ; ++z) {
philpem@5 19804 for (int y = 0; y<lY; ++y) {
philpem@5 19805 if (opacity>=1) {
philpem@5 19806 if (sizeof(T)!=1) { for (int x = 0; x<lX; ++x) *(ptrd++) = val; ptrd+=offX; }
philpem@5 19807 else { cimg_std::memset(ptrd,(int)val,lX); ptrd+=width; }
philpem@5 19808 } else { for (int x = 0; x<lX; ++x) { *ptrd = (T)(nopacity*val + *ptrd*copacity); ++ptrd; } ptrd+=offX; }
philpem@5 19809 }
philpem@5 19810 ptrd+=offY;
philpem@5 19811 }
philpem@5 19812 ptrd+=offZ;
philpem@5 19813 }
philpem@5 19814 return *this;
philpem@5 19815 }
philpem@5 19816
philpem@5 19817 //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
philpem@5 19818 /**
philpem@5 19819 \param x0 X-coordinate of the upper-left rectangle corner.
philpem@5 19820 \param y0 Y-coordinate of the upper-left rectangle corner.
philpem@5 19821 \param z0 Z-coordinate of the upper-left rectangle corner.
philpem@5 19822 \param x1 X-coordinate of the lower-right rectangle corner.
philpem@5 19823 \param y1 Y-coordinate of the lower-right rectangle corner.
philpem@5 19824 \param z1 Z-coordinate of the lower-right rectangle corner.
philpem@5 19825 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 19826 \param opacity Drawing opacity (optional).
philpem@5 19827 \note
philpem@5 19828 - Clipping is supported.
philpem@5 19829 **/
philpem@5 19830 template<typename tc>
philpem@5 19831 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
philpem@5 19832 const int x1, const int y1, const int z1,
philpem@5 19833 const tc *const color, const float opacity=1) {
philpem@5 19834 if (!color)
philpem@5 19835 throw CImgArgumentException("CImg<%s>::draw_rectangle : specified color is (null)",
philpem@5 19836 pixel_type());
philpem@5 19837 cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity);
philpem@5 19838 return *this;
philpem@5 19839 }
philpem@5 19840
philpem@5 19841 //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1).
philpem@5 19842 template<typename tc>
philpem@5 19843 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
philpem@5 19844 const int x1, const int y1, const int z1,
philpem@5 19845 const CImg<tc>& color, const float opacity=1) {
philpem@5 19846 return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity);
philpem@5 19847 }
philpem@5 19848
philpem@5 19849 //! Draw a 3D outlined colored rectangle in the instance image.
philpem@5 19850 template<typename tc>
philpem@5 19851 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
philpem@5 19852 const int x1, const int y1, const int z1,
philpem@5 19853 const tc *const color, const float opacity,
philpem@5 19854 const unsigned int pattern) {
philpem@5 19855 return draw_line(x0,y0,z0,x1,y0,z0,color,opacity,pattern,true).
philpem@5 19856 draw_line(x1,y0,z0,x1,y1,z0,color,opacity,pattern,false).
philpem@5 19857 draw_line(x1,y1,z0,x0,y1,z0,color,opacity,pattern,false).
philpem@5 19858 draw_line(x0,y1,z0,x0,y0,z0,color,opacity,pattern,false).
philpem@5 19859 draw_line(x0,y0,z1,x1,y0,z1,color,opacity,pattern,true).
philpem@5 19860 draw_line(x1,y0,z1,x1,y1,z1,color,opacity,pattern,false).
philpem@5 19861 draw_line(x1,y1,z1,x0,y1,z1,color,opacity,pattern,false).
philpem@5 19862 draw_line(x0,y1,z1,x0,y0,z1,color,opacity,pattern,false).
philpem@5 19863 draw_line(x0,y0,z0,x0,y0,z1,color,opacity,pattern,true).
philpem@5 19864 draw_line(x1,y0,z0,x1,y0,z1,color,opacity,pattern,true).
philpem@5 19865 draw_line(x1,y1,z0,x1,y1,z1,color,opacity,pattern,true).
philpem@5 19866 draw_line(x0,y1,z0,x0,y1,z1,color,opacity,pattern,true);
philpem@5 19867 }
philpem@5 19868
philpem@5 19869 //! Draw a 3D outlined colored rectangle in the instance image.
philpem@5 19870 template<typename tc>
philpem@5 19871 CImg<T>& draw_rectangle(const int x0, const int y0, const int z0,
philpem@5 19872 const int x1, const int y1, const int z1,
philpem@5 19873 const CImg<tc>& color, const float opacity,
philpem@5 19874 const unsigned int pattern) {
philpem@5 19875 return draw_rectangle(x0,y0,z0,x1,y1,z1,color.data,opacity,pattern);
philpem@5 19876 }
philpem@5 19877
philpem@5 19878 //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
philpem@5 19879 /**
philpem@5 19880 \param x0 X-coordinate of the upper-left rectangle corner.
philpem@5 19881 \param y0 Y-coordinate of the upper-left rectangle corner.
philpem@5 19882 \param x1 X-coordinate of the lower-right rectangle corner.
philpem@5 19883 \param y1 Y-coordinate of the lower-right rectangle corner.
philpem@5 19884 \param color Pointer to \c dimv() consecutive values of type \c T, defining the drawing color.
philpem@5 19885 \param opacity Drawing opacity (optional).
philpem@5 19886 \note
philpem@5 19887 - Clipping is supported.
philpem@5 19888 **/
philpem@5 19889 template<typename tc>
philpem@5 19890 CImg<T>& draw_rectangle(const int x0, const int y0,
philpem@5 19891 const int x1, const int y1,
philpem@5 19892 const tc *const color, const float opacity=1) {
philpem@5 19893 return draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity);
philpem@5 19894 }
philpem@5 19895
philpem@5 19896 //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1).
philpem@5 19897 template<typename tc>
philpem@5 19898 CImg<T>& draw_rectangle(const int x0, const int y0,
philpem@5 19899 const int x1, const int y1,
philpem@5 19900 const CImg<tc>& color, const float opacity=1) {
philpem@5 19901 return draw_rectangle(x0,y0,x1,y1,color.data,opacity);
philpem@5 19902 }
philpem@5 19903
philpem@5 19904 //! Draw a 2D outlined colored rectangle.
philpem@5 19905 template<typename tc>
philpem@5 19906 CImg<T>& draw_rectangle(const int x0, const int y0,
philpem@5 19907 const int x1, const int y1,
philpem@5 19908 const tc *const color, const float opacity,
philpem@5 19909 const unsigned int pattern) {
philpem@5 19910 if (is_empty()) return *this;
philpem@5 19911 if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
philpem@5 19912 if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
philpem@5 19913 const bool bx = (x0<x1), by = (y0<y1);
philpem@5 19914 const int
philpem@5 19915 nx0 = bx?x0:x1, nx1 = bx?x1:x0,
philpem@5 19916 ny0 = by?y0:y1, ny1 = by?y1:y0;
philpem@5 19917 if (ny1==ny0+1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
philpem@5 19918 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
philpem@5 19919 return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
philpem@5 19920 draw_line(nx1,ny0+1,nx1,ny1-1,color,opacity,pattern,false).
philpem@5 19921 draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false).
philpem@5 19922 draw_line(nx0,ny1-1,nx0,ny0+1,color,opacity,pattern,false);
philpem@5 19923 }
philpem@5 19924
philpem@5 19925 //! Draw a 2D outlined colored rectangle.
philpem@5 19926 template<typename tc>
philpem@5 19927 CImg<T>& draw_rectangle(const int x0, const int y0,
philpem@5 19928 const int x1, const int y1,
philpem@5 19929 const CImg<tc>& color, const float opacity,
philpem@5 19930 const unsigned int pattern) {
philpem@5 19931 return draw_rectangle(x0,y0,x1,y1,color.data,opacity,pattern);
philpem@5 19932 }
philpem@5 19933
philpem@5 19934 // Inner macro for drawing triangles.
philpem@5 19935 #define _cimg_for_triangle1(img,xl,xr,y,x0,y0,x1,y1,x2,y2) \
philpem@5 19936 for (int y = y0<0?0:y0, \
philpem@5 19937 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
philpem@5 19938 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
philpem@5 19939 _sxn=1, \
philpem@5 19940 _sxr=1, \
philpem@5 19941 _sxl=1, \
philpem@5 19942 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
philpem@5 19943 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
philpem@5 19944 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
philpem@5 19945 _dyn = y2-y1, \
philpem@5 19946 _dyr = y2-y0, \
philpem@5 19947 _dyl = y1-y0, \
philpem@5 19948 _counter = (_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
philpem@5 19949 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
philpem@5 19950 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
philpem@5 19951 cimg::min((int)(img).height-y-1,y2-y)), \
philpem@5 19952 _errn = _dyn/2, \
philpem@5 19953 _errr = _dyr/2, \
philpem@5 19954 _errl = _dyl/2, \
philpem@5 19955 _rxn = _dyn?(x2-x1)/_dyn:0, \
philpem@5 19956 _rxr = _dyr?(x2-x0)/_dyr:0, \
philpem@5 19957 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
philpem@5 19958 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn); \
philpem@5 19959 _counter>=0; --_counter, ++y, \
philpem@5 19960 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
philpem@5 19961 xl+=(y!=y1)?_rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0): \
philpem@5 19962 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
philpem@5 19963
philpem@5 19964 #define _cimg_for_triangle2(img,xl,cl,xr,cr,y,x0,y0,c0,x1,y1,c1,x2,y2,c2) \
philpem@5 19965 for (int y = y0<0?0:y0, \
philpem@5 19966 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
philpem@5 19967 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
philpem@5 19968 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
philpem@5 19969 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
philpem@5 19970 _sxn=1, _scn=1, \
philpem@5 19971 _sxr=1, _scr=1, \
philpem@5 19972 _sxl=1, _scl=1, \
philpem@5 19973 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
philpem@5 19974 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
philpem@5 19975 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
philpem@5 19976 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
philpem@5 19977 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
philpem@5 19978 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
philpem@5 19979 _dyn = y2-y1, \
philpem@5 19980 _dyr = y2-y0, \
philpem@5 19981 _dyl = y1-y0, \
philpem@5 19982 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
philpem@5 19983 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
philpem@5 19984 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
philpem@5 19985 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
philpem@5 19986 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
philpem@5 19987 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
philpem@5 19988 cimg::min((int)(img).height-y-1,y2-y)), \
philpem@5 19989 _errn = _dyn/2, _errcn = _errn, \
philpem@5 19990 _errr = _dyr/2, _errcr = _errr, \
philpem@5 19991 _errl = _dyl/2, _errcl = _errl, \
philpem@5 19992 _rxn = _dyn?(x2-x1)/_dyn:0, \
philpem@5 19993 _rcn = _dyn?(c2-c1)/_dyn:0, \
philpem@5 19994 _rxr = _dyr?(x2-x0)/_dyr:0, \
philpem@5 19995 _rcr = _dyr?(c2-c0)/_dyr:0, \
philpem@5 19996 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
philpem@5 19997 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
philpem@5 19998 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
philpem@5 19999 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ); \
philpem@5 20000 _counter>=0; --_counter, ++y, \
philpem@5 20001 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
philpem@5 20002 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
philpem@5 20003 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
philpem@5 20004 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
philpem@5 20005 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
philpem@5 20006 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
philpem@5 20007
philpem@5 20008 #define _cimg_for_triangle3(img,xl,txl,tyl,xr,txr,tyr,y,x0,y0,tx0,ty0,x1,y1,tx1,ty1,x2,y2,tx2,ty2) \
philpem@5 20009 for (int y = y0<0?0:y0, \
philpem@5 20010 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
philpem@5 20011 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
philpem@5 20012 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
philpem@5 20013 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
philpem@5 20014 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
philpem@5 20015 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
philpem@5 20016 _sxn=1, _stxn=1, _styn=1, \
philpem@5 20017 _sxr=1, _stxr=1, _styr=1, \
philpem@5 20018 _sxl=1, _stxl=1, _styl=1, \
philpem@5 20019 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
philpem@5 20020 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
philpem@5 20021 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
philpem@5 20022 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
philpem@5 20023 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
philpem@5 20024 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
philpem@5 20025 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
philpem@5 20026 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
philpem@5 20027 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
philpem@5 20028 _dyn = y2-y1, \
philpem@5 20029 _dyr = y2-y0, \
philpem@5 20030 _dyl = y1-y0, \
philpem@5 20031 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
philpem@5 20032 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
philpem@5 20033 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
philpem@5 20034 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
philpem@5 20035 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
philpem@5 20036 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
philpem@5 20037 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
philpem@5 20038 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
philpem@5 20039 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
philpem@5 20040 cimg::min((int)(img).height-y-1,y2-y)), \
philpem@5 20041 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, \
philpem@5 20042 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, \
philpem@5 20043 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, \
philpem@5 20044 _rxn = _dyn?(x2-x1)/_dyn:0, \
philpem@5 20045 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
philpem@5 20046 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
philpem@5 20047 _rxr = _dyr?(x2-x0)/_dyr:0, \
philpem@5 20048 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
philpem@5 20049 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
philpem@5 20050 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
philpem@5 20051 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
philpem@5 20052 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
philpem@5 20053 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
philpem@5 20054 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
philpem@5 20055 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
philpem@5 20056 _counter>=0; --_counter, ++y, \
philpem@5 20057 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
philpem@5 20058 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
philpem@5 20059 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
philpem@5 20060 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
philpem@5 20061 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
philpem@5 20062 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
philpem@5 20063 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
philpem@5 20064 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1,\
philpem@5 20065 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
philpem@5 20066
philpem@5 20067 #define _cimg_for_triangle4(img,xl,cl,txl,tyl,xr,cr,txr,tyr,y,x0,y0,c0,tx0,ty0,x1,y1,c1,tx1,ty1,x2,y2,c2,tx2,ty2) \
philpem@5 20068 for (int y = y0<0?0:y0, \
philpem@5 20069 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
philpem@5 20070 cr = y0>=0?c0:(c0-y0*(c2-c0)/(y2-y0)), \
philpem@5 20071 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
philpem@5 20072 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
philpem@5 20073 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
philpem@5 20074 cl = y1>=0?(y0>=0?(y0==y1?c1:c0):(c0-y0*(c1-c0)/(y1-y0))):(c1-y1*(c2-c1)/(y2-y1)), \
philpem@5 20075 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
philpem@5 20076 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
philpem@5 20077 _sxn=1, _scn=1, _stxn=1, _styn=1, \
philpem@5 20078 _sxr=1, _scr=1, _stxr=1, _styr=1, \
philpem@5 20079 _sxl=1, _scl=1, _stxl=1, _styl=1, \
philpem@5 20080 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), \
philpem@5 20081 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), \
philpem@5 20082 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), \
philpem@5 20083 _dcn = c2>c1?c2-c1:(_scn=-1,c1-c2), \
philpem@5 20084 _dcr = c2>c0?c2-c0:(_scr=-1,c0-c2), \
philpem@5 20085 _dcl = c1>c0?c1-c0:(_scl=-1,c0-c1), \
philpem@5 20086 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
philpem@5 20087 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
philpem@5 20088 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
philpem@5 20089 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
philpem@5 20090 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
philpem@5 20091 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
philpem@5 20092 _dyn = y2-y1, \
philpem@5 20093 _dyr = y2-y0, \
philpem@5 20094 _dyl = y1-y0, \
philpem@5 20095 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
philpem@5 20096 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
philpem@5 20097 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
philpem@5 20098 _dcn-=_dyn?_dyn*(_dcn/_dyn):0, \
philpem@5 20099 _dcr-=_dyr?_dyr*(_dcr/_dyr):0, \
philpem@5 20100 _dcl-=_dyl?_dyl*(_dcl/_dyl):0, \
philpem@5 20101 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
philpem@5 20102 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
philpem@5 20103 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
philpem@5 20104 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
philpem@5 20105 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
philpem@5 20106 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
philpem@5 20107 cimg::min((int)(img).height-y-1,y2-y)), \
philpem@5 20108 _errn = _dyn/2, _errcn = _errn, _errtxn = _errn, _errtyn = _errn, \
philpem@5 20109 _errr = _dyr/2, _errcr = _errr, _errtxr = _errr, _errtyr = _errr, \
philpem@5 20110 _errl = _dyl/2, _errcl = _errl, _errtxl = _errl, _errtyl = _errl, \
philpem@5 20111 _rxn = _dyn?(x2-x1)/_dyn:0, \
philpem@5 20112 _rcn = _dyn?(c2-c1)/_dyn:0, \
philpem@5 20113 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
philpem@5 20114 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
philpem@5 20115 _rxr = _dyr?(x2-x0)/_dyr:0, \
philpem@5 20116 _rcr = _dyr?(c2-c0)/_dyr:0, \
philpem@5 20117 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
philpem@5 20118 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
philpem@5 20119 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
philpem@5 20120 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
philpem@5 20121 _rcl = (y0!=y1 && y1>0)?(_dyl?(c1-c0)/_dyl:0): \
philpem@5 20122 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcn ), \
philpem@5 20123 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
philpem@5 20124 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
philpem@5 20125 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
philpem@5 20126 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ); \
philpem@5 20127 _counter>=0; --_counter, ++y, \
philpem@5 20128 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
philpem@5 20129 cr+=_rcr+((_errcr-=_dcr)<0?_errcr+=_dyr,_scr:0), \
philpem@5 20130 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
philpem@5 20131 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
philpem@5 20132 xl+=(y!=y1)?(cl+=_rcl+((_errcl-=_dcl)<0?(_errcl+=_dyl,_scl):0), \
philpem@5 20133 txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
philpem@5 20134 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
philpem@5 20135 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
philpem@5 20136 (_errcl=_errcn, _dcl=_dcn, _dyl=_dyn, _scl=_scn, _rcl=_rcn, cl=c1, \
philpem@5 20137 _errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
philpem@5 20138 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
philpem@5 20139 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
philpem@5 20140
philpem@5 20141 #define _cimg_for_triangle5(img,xl,txl,tyl,lxl,lyl,xr,txr,tyr,lxr,lyr,y,x0,y0,tx0,ty0,lx0,ly0,x1,y1,tx1,ty1,lx1,ly1,x2,y2,tx2,ty2,lx2,ly2) \
philpem@5 20142 for (int y = y0<0?0:y0, \
philpem@5 20143 xr = y0>=0?x0:(x0-y0*(x2-x0)/(y2-y0)), \
philpem@5 20144 txr = y0>=0?tx0:(tx0-y0*(tx2-tx0)/(y2-y0)), \
philpem@5 20145 tyr = y0>=0?ty0:(ty0-y0*(ty2-ty0)/(y2-y0)), \
philpem@5 20146 lxr = y0>=0?lx0:(lx0-y0*(lx2-lx0)/(y2-y0)), \
philpem@5 20147 lyr = y0>=0?ly0:(ly0-y0*(ly2-ly0)/(y2-y0)), \
philpem@5 20148 xl = y1>=0?(y0>=0?(y0==y1?x1:x0):(x0-y0*(x1-x0)/(y1-y0))):(x1-y1*(x2-x1)/(y2-y1)), \
philpem@5 20149 txl = y1>=0?(y0>=0?(y0==y1?tx1:tx0):(tx0-y0*(tx1-tx0)/(y1-y0))):(tx1-y1*(tx2-tx1)/(y2-y1)), \
philpem@5 20150 tyl = y1>=0?(y0>=0?(y0==y1?ty1:ty0):(ty0-y0*(ty1-ty0)/(y1-y0))):(ty1-y1*(ty2-ty1)/(y2-y1)), \
philpem@5 20151 lxl = y1>=0?(y0>=0?(y0==y1?lx1:lx0):(lx0-y0*(lx1-lx0)/(y1-y0))):(lx1-y1*(lx2-lx1)/(y2-y1)), \
philpem@5 20152 lyl = y1>=0?(y0>=0?(y0==y1?ly1:ly0):(ly0-y0*(ly1-ly0)/(y1-y0))):(ly1-y1*(ly2-ly1)/(y2-y1)), \
philpem@5 20153 _sxn=1, _stxn=1, _styn=1, _slxn=1, _slyn=1, \
philpem@5 20154 _sxr=1, _stxr=1, _styr=1, _slxr=1, _slyr=1, \
philpem@5 20155 _sxl=1, _stxl=1, _styl=1, _slxl=1, _slyl=1, \
philpem@5 20156 _dxn = x2>x1?x2-x1:(_sxn=-1,x1-x2), _dyn = y2-y1, \
philpem@5 20157 _dxr = x2>x0?x2-x0:(_sxr=-1,x0-x2), _dyr = y2-y0, \
philpem@5 20158 _dxl = x1>x0?x1-x0:(_sxl=-1,x0-x1), _dyl = y1-y0, \
philpem@5 20159 _dtxn = tx2>tx1?tx2-tx1:(_stxn=-1,tx1-tx2), \
philpem@5 20160 _dtxr = tx2>tx0?tx2-tx0:(_stxr=-1,tx0-tx2), \
philpem@5 20161 _dtxl = tx1>tx0?tx1-tx0:(_stxl=-1,tx0-tx1), \
philpem@5 20162 _dtyn = ty2>ty1?ty2-ty1:(_styn=-1,ty1-ty2), \
philpem@5 20163 _dtyr = ty2>ty0?ty2-ty0:(_styr=-1,ty0-ty2), \
philpem@5 20164 _dtyl = ty1>ty0?ty1-ty0:(_styl=-1,ty0-ty1), \
philpem@5 20165 _dlxn = lx2>lx1?lx2-lx1:(_slxn=-1,lx1-lx2), \
philpem@5 20166 _dlxr = lx2>lx0?lx2-lx0:(_slxr=-1,lx0-lx2), \
philpem@5 20167 _dlxl = lx1>lx0?lx1-lx0:(_slxl=-1,lx0-lx1), \
philpem@5 20168 _dlyn = ly2>ly1?ly2-ly1:(_slyn=-1,ly1-ly2), \
philpem@5 20169 _dlyr = ly2>ly0?ly2-ly0:(_slyr=-1,ly0-ly2), \
philpem@5 20170 _dlyl = ly1>ly0?ly1-ly0:(_slyl=-1,ly0-ly1), \
philpem@5 20171 _counter =(_dxn-=_dyn?_dyn*(_dxn/_dyn):0, \
philpem@5 20172 _dxr-=_dyr?_dyr*(_dxr/_dyr):0, \
philpem@5 20173 _dxl-=_dyl?_dyl*(_dxl/_dyl):0, \
philpem@5 20174 _dtxn-=_dyn?_dyn*(_dtxn/_dyn):0, \
philpem@5 20175 _dtxr-=_dyr?_dyr*(_dtxr/_dyr):0, \
philpem@5 20176 _dtxl-=_dyl?_dyl*(_dtxl/_dyl):0, \
philpem@5 20177 _dtyn-=_dyn?_dyn*(_dtyn/_dyn):0, \
philpem@5 20178 _dtyr-=_dyr?_dyr*(_dtyr/_dyr):0, \
philpem@5 20179 _dtyl-=_dyl?_dyl*(_dtyl/_dyl):0, \
philpem@5 20180 _dlxn-=_dyn?_dyn*(_dlxn/_dyn):0, \
philpem@5 20181 _dlxr-=_dyr?_dyr*(_dlxr/_dyr):0, \
philpem@5 20182 _dlxl-=_dyl?_dyl*(_dlxl/_dyl):0, \
philpem@5 20183 _dlyn-=_dyn?_dyn*(_dlyn/_dyn):0, \
philpem@5 20184 _dlyr-=_dyr?_dyr*(_dlyr/_dyr):0, \
philpem@5 20185 _dlyl-=_dyl?_dyl*(_dlyl/_dyl):0, \
philpem@5 20186 cimg::min((int)(img).height-y-1,y2-y)), \
philpem@5 20187 _errn = _dyn/2, _errtxn = _errn, _errtyn = _errn, _errlxn = _errn, _errlyn = _errn, \
philpem@5 20188 _errr = _dyr/2, _errtxr = _errr, _errtyr = _errr, _errlxr = _errr, _errlyr = _errr, \
philpem@5 20189 _errl = _dyl/2, _errtxl = _errl, _errtyl = _errl, _errlxl = _errl, _errlyl = _errl, \
philpem@5 20190 _rxn = _dyn?(x2-x1)/_dyn:0, \
philpem@5 20191 _rtxn = _dyn?(tx2-tx1)/_dyn:0, \
philpem@5 20192 _rtyn = _dyn?(ty2-ty1)/_dyn:0, \
philpem@5 20193 _rlxn = _dyn?(lx2-lx1)/_dyn:0, \
philpem@5 20194 _rlyn = _dyn?(ly2-ly1)/_dyn:0, \
philpem@5 20195 _rxr = _dyr?(x2-x0)/_dyr:0, \
philpem@5 20196 _rtxr = _dyr?(tx2-tx0)/_dyr:0, \
philpem@5 20197 _rtyr = _dyr?(ty2-ty0)/_dyr:0, \
philpem@5 20198 _rlxr = _dyr?(lx2-lx0)/_dyr:0, \
philpem@5 20199 _rlyr = _dyr?(ly2-ly0)/_dyr:0, \
philpem@5 20200 _rxl = (y0!=y1 && y1>0)?(_dyl?(x1-x0)/_dyl:0): \
philpem@5 20201 (_errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxn), \
philpem@5 20202 _rtxl = (y0!=y1 && y1>0)?(_dyl?(tx1-tx0)/_dyl:0): \
philpem@5 20203 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxn ), \
philpem@5 20204 _rtyl = (y0!=y1 && y1>0)?(_dyl?(ty1-ty0)/_dyl:0): \
philpem@5 20205 (_errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyn ), \
philpem@5 20206 _rlxl = (y0!=y1 && y1>0)?(_dyl?(lx1-lx0)/_dyl:0): \
philpem@5 20207 (_errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxn ), \
philpem@5 20208 _rlyl = (y0!=y1 && y1>0)?(_dyl?(ly1-ly0)/_dyl:0): \
philpem@5 20209 (_errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyn ); \
philpem@5 20210 _counter>=0; --_counter, ++y, \
philpem@5 20211 xr+=_rxr+((_errr-=_dxr)<0?_errr+=_dyr,_sxr:0), \
philpem@5 20212 txr+=_rtxr+((_errtxr-=_dtxr)<0?_errtxr+=_dyr,_stxr:0), \
philpem@5 20213 tyr+=_rtyr+((_errtyr-=_dtyr)<0?_errtyr+=_dyr,_styr:0), \
philpem@5 20214 lxr+=_rlxr+((_errlxr-=_dlxr)<0?_errlxr+=_dyr,_slxr:0), \
philpem@5 20215 lyr+=_rlyr+((_errlyr-=_dlyr)<0?_errlyr+=_dyr,_slyr:0), \
philpem@5 20216 xl+=(y!=y1)?(txl+=_rtxl+((_errtxl-=_dtxl)<0?(_errtxl+=_dyl,_stxl):0), \
philpem@5 20217 tyl+=_rtyl+((_errtyl-=_dtyl)<0?(_errtyl+=_dyl,_styl):0), \
philpem@5 20218 lxl+=_rlxl+((_errlxl-=_dlxl)<0?(_errlxl+=_dyl,_slxl):0), \
philpem@5 20219 lyl+=_rlyl+((_errlyl-=_dlyl)<0?(_errlyl+=_dyl,_slyl):0), \
philpem@5 20220 _rxl+((_errl-=_dxl)<0?(_errl+=_dyl,_sxl):0)): \
philpem@5 20221 (_errtxl=_errtxn, _dtxl=_dtxn, _dyl=_dyn, _stxl=_stxn, _rtxl=_rtxn, txl=tx1, \
philpem@5 20222 _errtyl=_errtyn, _dtyl=_dtyn, _dyl=_dyn, _styl=_styn, _rtyl=_rtyn, tyl=ty1, \
philpem@5 20223 _errlxl=_errlxn, _dlxl=_dlxn, _dyl=_dyn, _slxl=_slxn, _rlxl=_rlxn, lxl=lx1, \
philpem@5 20224 _errlyl=_errlyn, _dlyl=_dlyn, _dyl=_dyn, _slyl=_slyn, _rlyl=_rlyn, lyl=ly1, \
philpem@5 20225 _errl=_errn, _dxl=_dxn, _dyl=_dyn, _sxl=_sxn, _rxl=_rxn, x1-xl))
philpem@5 20226
philpem@5 20227 // Draw a colored triangle (inner routine, uses bresenham's algorithm).
philpem@5 20228 template<typename tc>
philpem@5 20229 CImg<T>& _draw_triangle(const int x0, const int y0,
philpem@5 20230 const int x1, const int y1,
philpem@5 20231 const int x2, const int y2,
philpem@5 20232 const tc *const color, const float opacity,
philpem@5 20233 const float brightness) {
philpem@5 20234 _draw_scanline(color,opacity);
philpem@5 20235 const float nbrightness = brightness<0?0:(brightness>2?2:brightness);
philpem@5 20236 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
philpem@5 20237 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1);
philpem@5 20238 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2);
philpem@5 20239 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2);
philpem@5 20240 if (ny0<dimy() && ny2>=0) {
philpem@5 20241 if ((nx1 - nx0)*(ny2 - ny0) - (nx2 - nx0)*(ny1 - ny0)<0)
philpem@5 20242 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xl,xr,y,color,opacity,nbrightness);
philpem@5 20243 else
philpem@5 20244 _cimg_for_triangle1(*this,xl,xr,y,nx0,ny0,nx1,ny1,nx2,ny2) _draw_scanline(xr,xl,y,color,opacity,nbrightness);
philpem@5 20245 }
philpem@5 20246 return *this;
philpem@5 20247 }
philpem@5 20248
philpem@5 20249 //! Draw a 2D filled colored triangle.
philpem@5 20250 template<typename tc>
philpem@5 20251 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20252 const int x1, const int y1,
philpem@5 20253 const int x2, const int y2,
philpem@5 20254 const tc *const color, const float opacity=1) {
philpem@5 20255 if (is_empty()) return *this;
philpem@5 20256 if (!color)
philpem@5 20257 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
philpem@5 20258 pixel_type());
philpem@5 20259 _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1);
philpem@5 20260 return *this;
philpem@5 20261 }
philpem@5 20262
philpem@5 20263 //! Draw a 2D filled colored triangle.
philpem@5 20264 template<typename tc>
philpem@5 20265 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20266 const int x1, const int y1,
philpem@5 20267 const int x2, const int y2,
philpem@5 20268 const CImg<tc>& color, const float opacity=1) {
philpem@5 20269 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity);
philpem@5 20270 }
philpem@5 20271
philpem@5 20272 //! Draw a 2D outlined colored triangle.
philpem@5 20273 template<typename tc>
philpem@5 20274 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20275 const int x1, const int y1,
philpem@5 20276 const int x2, const int y2,
philpem@5 20277 const tc *const color, const float opacity,
philpem@5 20278 const unsigned int pattern) {
philpem@5 20279 if (is_empty()) return *this;
philpem@5 20280 if (!color)
philpem@5 20281 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
philpem@5 20282 pixel_type());
philpem@5 20283 draw_line(x0,y0,x1,y1,color,opacity,pattern,true).
philpem@5 20284 draw_line(x1,y1,x2,y2,color,opacity,pattern,false).
philpem@5 20285 draw_line(x2,y2,x0,y0,color,opacity,pattern,false);
philpem@5 20286 return *this;
philpem@5 20287 }
philpem@5 20288
philpem@5 20289 //! Draw a 2D outlined colored triangle.
philpem@5 20290 template<typename tc>
philpem@5 20291 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20292 const int x1, const int y1,
philpem@5 20293 const int x2, const int y2,
philpem@5 20294 const CImg<tc>& color, const float opacity,
philpem@5 20295 const unsigned int pattern) {
philpem@5 20296 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opacity,pattern);
philpem@5 20297 }
philpem@5 20298
philpem@5 20299 //! Draw a 2D filled colored triangle, with z-buffering.
philpem@5 20300 template<typename tc>
philpem@5 20301 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 20302 const int x0, const int y0, const float z0,
philpem@5 20303 const int x1, const int y1, const float z1,
philpem@5 20304 const int x2, const int y2, const float z2,
philpem@5 20305 const tc *const color, const float opacity=1,
philpem@5 20306 const float brightness=1) {
philpem@5 20307 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 20308 if (!color)
philpem@5 20309 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
philpem@5 20310 pixel_type());
philpem@5 20311 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20312 const float
philpem@5 20313 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
philpem@5 20314 nbrightness = brightness<0?0:(brightness>2?2:brightness);
philpem@5 20315 const int whz = width*height*depth, offx = dim*whz;
philpem@5 20316 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
philpem@5 20317 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 20318 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1);
philpem@5 20319 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2);
philpem@5 20320 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2);
philpem@5 20321 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20322 float
philpem@5 20323 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 20324 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 20325 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 20326 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 20327 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
philpem@5 20328 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
philpem@5 20329 if (y==ny1) { zl = nz1; pzl = pzn; }
philpem@5 20330 int xleft = xleft0, xright = xright0;
philpem@5 20331 float zleft = zl, zright = zr;
philpem@5 20332 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright);
philpem@5 20333 const int dx = xright - xleft;
philpem@5 20334 const float pentez = (zright - zleft)/dx;
philpem@5 20335 if (xleft<0 && dx) zleft-=xleft*(zright - zleft)/dx;
philpem@5 20336 if (xleft<0) xleft = 0;
philpem@5 20337 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20338 T* ptrd = ptr(xleft,y,0,0);
philpem@5 20339 float *ptrz = zbuffer + xleft + y*width;
philpem@5 20340 if (opacity>=1) {
philpem@5 20341 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20342 if (zleft>*ptrz) {
philpem@5 20343 *ptrz = zleft;
philpem@5 20344 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; }
philpem@5 20345 ptrd-=offx;
philpem@5 20346 }
philpem@5 20347 zleft+=pentez;
philpem@5 20348 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20349 if (zleft>*ptrz) {
philpem@5 20350 *ptrz = zleft;
philpem@5 20351 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nbrightness*(*col++)); ptrd+=whz; }
philpem@5 20352 ptrd-=offx;
philpem@5 20353 }
philpem@5 20354 zleft+=pentez;
philpem@5 20355 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20356 if (zleft>*ptrz) {
philpem@5 20357 *ptrz = zleft;
philpem@5 20358 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval); ptrd+=whz; }
philpem@5 20359 ptrd-=offx;
philpem@5 20360 }
philpem@5 20361 zleft+=pentez;
philpem@5 20362 }
philpem@5 20363 } else {
philpem@5 20364 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20365 if (zleft>*ptrz) {
philpem@5 20366 *ptrz = zleft;
philpem@5 20367 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity**(col++) + *ptrd*copacity); ptrd+=whz; }
philpem@5 20368 ptrd-=offx;
philpem@5 20369 }
philpem@5 20370 zleft+=pentez;
philpem@5 20371 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20372 if (zleft>*ptrz) {
philpem@5 20373 *ptrz = zleft;
philpem@5 20374 const tc *col = color; cimg_forV(*this,k) { *ptrd = (T)(nopacity*nbrightness**(col++) + *ptrd*copacity); ptrd+=whz; }
philpem@5 20375 ptrd-=offx;
philpem@5 20376 }
philpem@5 20377 zleft+=pentez;
philpem@5 20378 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20379 if (zleft>*ptrz) {
philpem@5 20380 *ptrz = zleft;
philpem@5 20381 const tc *col = color;
philpem@5 20382 cimg_forV(*this,k) {
philpem@5 20383 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
philpem@5 20384 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20385 ptrd+=whz;
philpem@5 20386 }
philpem@5 20387 ptrd-=offx;
philpem@5 20388 }
philpem@5 20389 zleft+=pentez;
philpem@5 20390 }
philpem@5 20391 }
philpem@5 20392 zr+=pzr; zl+=pzl;
philpem@5 20393 }
philpem@5 20394 return *this;
philpem@5 20395 }
philpem@5 20396
philpem@5 20397 //! Draw a 2D filled colored triangle, with z-buffering.
philpem@5 20398 template<typename tc>
philpem@5 20399 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 20400 const int x0, const int y0, const float z0,
philpem@5 20401 const int x1, const int y1, const float z1,
philpem@5 20402 const int x2, const int y2, const float z2,
philpem@5 20403 const CImg<tc>& color, const float opacity=1,
philpem@5 20404 const float brightness=1) {
philpem@5 20405 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opacity,brightness);
philpem@5 20406 }
philpem@5 20407
philpem@5 20408 //! Draw a 2D Gouraud-shaded colored triangle.
philpem@5 20409 /**
philpem@5 20410 \param x0 = X-coordinate of the first corner in the instance image.
philpem@5 20411 \param y0 = Y-coordinate of the first corner in the instance image.
philpem@5 20412 \param x1 = X-coordinate of the second corner in the instance image.
philpem@5 20413 \param y1 = Y-coordinate of the second corner in the instance image.
philpem@5 20414 \param x2 = X-coordinate of the third corner in the instance image.
philpem@5 20415 \param y2 = Y-coordinate of the third corner in the instance image.
philpem@5 20416 \param color = array of dimv() values of type \c T, defining the global drawing color.
philpem@5 20417 \param brightness0 = brightness of the first corner (in [0,2]).
philpem@5 20418 \param brightness1 = brightness of the second corner (in [0,2]).
philpem@5 20419 \param brightness2 = brightness of the third corner (in [0,2]).
philpem@5 20420 \param opacity = opacity of the drawing.
philpem@5 20421 \note Clipping is supported.
philpem@5 20422 **/
philpem@5 20423 template<typename tc>
philpem@5 20424 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20425 const int x1, const int y1,
philpem@5 20426 const int x2, const int y2,
philpem@5 20427 const tc *const color,
philpem@5 20428 const float brightness0,
philpem@5 20429 const float brightness1,
philpem@5 20430 const float brightness2,
philpem@5 20431 const float opacity=1) {
philpem@5 20432 if (is_empty()) return *this;
philpem@5 20433 if (!color)
philpem@5 20434 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
philpem@5 20435 pixel_type());
philpem@5 20436 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20437 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 20438 const int whz = width*height*depth, offx = dim*whz-1;
philpem@5 20439 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 20440 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
philpem@5 20441 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
philpem@5 20442 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
philpem@5 20443 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1);
philpem@5 20444 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2);
philpem@5 20445 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2);
philpem@5 20446 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20447 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
philpem@5 20448 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
philpem@5 20449 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright);
philpem@5 20450 const int
philpem@5 20451 dx = xright - xleft,
philpem@5 20452 dc = cright>cleft?cright - cleft:cleft - cright,
philpem@5 20453 rc = dx?(cright - cleft)/dx:0,
philpem@5 20454 sc = cright>cleft?1:-1,
philpem@5 20455 ndc = dc-(dx?dx*(dc/dx):0);
philpem@5 20456 int errc = dx>>1;
philpem@5 20457 if (xleft<0 && dx) cleft-=xleft*(cright - cleft)/dx;
philpem@5 20458 if (xleft<0) xleft = 0;
philpem@5 20459 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20460 T* ptrd = ptr(xleft,y);
philpem@5 20461 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20462 const tc *col = color;
philpem@5 20463 cimg_forV(*this,k) {
philpem@5 20464 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
philpem@5 20465 ptrd+=whz;
philpem@5 20466 }
philpem@5 20467 ptrd-=offx;
philpem@5 20468 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 20469 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 20470 const tc *col = color;
philpem@5 20471 cimg_forV(*this,k) {
philpem@5 20472 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
philpem@5 20473 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20474 ptrd+=whz;
philpem@5 20475 }
philpem@5 20476 ptrd-=offx;
philpem@5 20477 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 20478 }
philpem@5 20479 }
philpem@5 20480 return *this;
philpem@5 20481 }
philpem@5 20482
philpem@5 20483 //! Draw a 2D Gouraud-shaded colored triangle.
philpem@5 20484 template<typename tc>
philpem@5 20485 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20486 const int x1, const int y1,
philpem@5 20487 const int x2, const int y2,
philpem@5 20488 const CImg<tc>& color,
philpem@5 20489 const float brightness0,
philpem@5 20490 const float brightness1,
philpem@5 20491 const float brightness2,
philpem@5 20492 const float opacity=1) {
philpem@5 20493 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,brightness0,brightness1,brightness2,opacity);
philpem@5 20494 }
philpem@5 20495
philpem@5 20496 //! Draw a 2D Gouraud-shaded colored triangle, with z-buffering.
philpem@5 20497 template<typename tc>
philpem@5 20498 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 20499 const int x0, const int y0, const float z0,
philpem@5 20500 const int x1, const int y1, const float z1,
philpem@5 20501 const int x2, const int y2, const float z2,
philpem@5 20502 const tc *const color,
philpem@5 20503 const float brightness0,
philpem@5 20504 const float brightness1,
philpem@5 20505 const float brightness2,
philpem@5 20506 const float opacity=1) {
philpem@5 20507 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 20508 if (!color)
philpem@5 20509 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
philpem@5 20510 pixel_type());
philpem@5 20511 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20512 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 20513 const int whz = width*height*depth, offx = dim*whz;
philpem@5 20514 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 20515 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
philpem@5 20516 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
philpem@5 20517 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
philpem@5 20518 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 20519 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1,nc0,nc1);
philpem@5 20520 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nz0,nz2,nc0,nc2);
philpem@5 20521 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nz1,nz2,nc1,nc2);
philpem@5 20522 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20523 float
philpem@5 20524 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 20525 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 20526 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 20527 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 20528 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
philpem@5 20529 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
philpem@5 20530 if (y==ny1) { zl = nz1; pzl = pzn; }
philpem@5 20531 int xleft = xleft0, xright = xright0, cleft = cleft0, cright = cright0;
philpem@5 20532 float zleft = zl, zright = zr;
philpem@5 20533 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,cleft,cright);
philpem@5 20534 const int
philpem@5 20535 dx = xright - xleft,
philpem@5 20536 dc = cright>cleft?cright - cleft:cleft - cright,
philpem@5 20537 rc = dx?(cright-cleft)/dx:0,
philpem@5 20538 sc = cright>cleft?1:-1,
philpem@5 20539 ndc = dc-(dx?dx*(dc/dx):0);
philpem@5 20540 const float pentez = (zright - zleft)/dx;
philpem@5 20541 int errc = dx>>1;
philpem@5 20542 if (xleft<0 && dx) {
philpem@5 20543 cleft-=xleft*(cright - cleft)/dx;
philpem@5 20544 zleft-=xleft*(zright - zleft)/dx;
philpem@5 20545 }
philpem@5 20546 if (xleft<0) xleft = 0;
philpem@5 20547 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20548 T *ptrd = ptr(xleft,y);
philpem@5 20549 float *ptrz = zbuffer + xleft + y*width;
philpem@5 20550 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
philpem@5 20551 if (zleft>*ptrz) {
philpem@5 20552 *ptrz = zleft;
philpem@5 20553 const tc *col = color;
philpem@5 20554 cimg_forV(*this,k) {
philpem@5 20555 *ptrd = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
philpem@5 20556 ptrd+=whz;
philpem@5 20557 }
philpem@5 20558 ptrd-=offx;
philpem@5 20559 }
philpem@5 20560 zleft+=pentez;
philpem@5 20561 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 20562 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
philpem@5 20563 if (zleft>*ptrz) {
philpem@5 20564 *ptrz = zleft;
philpem@5 20565 const tc *col = color;
philpem@5 20566 cimg_forV(*this,k) {
philpem@5 20567 const T val = (T)(cleft<256?cleft**(col++)/256:((512-cleft)**(col++)+(cleft-256)*maxval)/256);
philpem@5 20568 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20569 ptrd+=whz;
philpem@5 20570 }
philpem@5 20571 ptrd-=offx;
philpem@5 20572 }
philpem@5 20573 zleft+=pentez;
philpem@5 20574 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 20575 }
philpem@5 20576 zr+=pzr; zl+=pzl;
philpem@5 20577 }
philpem@5 20578 return *this;
philpem@5 20579 }
philpem@5 20580
philpem@5 20581 //! Draw a Gouraud triangle with z-buffer consideration.
philpem@5 20582 template<typename tc>
philpem@5 20583 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 20584 const int x0, const int y0, const float z0,
philpem@5 20585 const int x1, const int y1, const float z1,
philpem@5 20586 const int x2, const int y2, const float z2,
philpem@5 20587 const CImg<tc>& color,
philpem@5 20588 const float brightness0,
philpem@5 20589 const float brightness1,
philpem@5 20590 const float brightness2,
philpem@5 20591 const float opacity=1) {
philpem@5 20592 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,brightness0,brightness1,brightness2,opacity);
philpem@5 20593 }
philpem@5 20594
philpem@5 20595 //! Draw a 2D textured triangle.
philpem@5 20596 /**
philpem@5 20597 \param x0 = X-coordinate of the first corner in the instance image.
philpem@5 20598 \param y0 = Y-coordinate of the first corner in the instance image.
philpem@5 20599 \param x1 = X-coordinate of the second corner in the instance image.
philpem@5 20600 \param y1 = Y-coordinate of the second corner in the instance image.
philpem@5 20601 \param x2 = X-coordinate of the third corner in the instance image.
philpem@5 20602 \param y2 = Y-coordinate of the third corner in the instance image.
philpem@5 20603 \param texture = texture image used to fill the triangle.
philpem@5 20604 \param tx0 = X-coordinate of the first corner in the texture image.
philpem@5 20605 \param ty0 = Y-coordinate of the first corner in the texture image.
philpem@5 20606 \param tx1 = X-coordinate of the second corner in the texture image.
philpem@5 20607 \param ty1 = Y-coordinate of the second corner in the texture image.
philpem@5 20608 \param tx2 = X-coordinate of the third corner in the texture image.
philpem@5 20609 \param ty2 = Y-coordinate of the third corner in the texture image.
philpem@5 20610 \param opacity = opacity of the drawing.
philpem@5 20611 \param brightness = brightness of the drawing (in [0,2]).
philpem@5 20612 \note Clipping is supported, but texture coordinates do not support clipping.
philpem@5 20613 **/
philpem@5 20614 template<typename tc>
philpem@5 20615 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 20616 const int x1, const int y1,
philpem@5 20617 const int x2, const int y2,
philpem@5 20618 const CImg<tc>& texture,
philpem@5 20619 const int tx0, const int ty0,
philpem@5 20620 const int tx1, const int ty1,
philpem@5 20621 const int tx2, const int ty2,
philpem@5 20622 const float opacity=1,
philpem@5 20623 const float brightness=1) {
philpem@5 20624 if (is_empty()) return *this;
philpem@5 20625 if (!texture || texture.dim<dim)
philpem@5 20626 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 20627 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 20628 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
philpem@5 20629 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20630 const float
philpem@5 20631 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
philpem@5 20632 nbrightness = brightness<0?0:(brightness>2?2:brightness);
philpem@5 20633 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 20634 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 20635 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2;
philpem@5 20636 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1);
philpem@5 20637 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2);
philpem@5 20638 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2);
philpem@5 20639 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20640 _cimg_for_triangle3(*this,xleft0,txleft0,tyleft0,xright0,txright0,tyright0,y,
philpem@5 20641 nx0,ny0,ntx0,nty0,nx1,ny1,ntx1,nty1,nx2,ny2,ntx2,nty2) {
philpem@5 20642 int
philpem@5 20643 xleft = xleft0, xright = xright0,
philpem@5 20644 txleft = txleft0, txright = txright0,
philpem@5 20645 tyleft = tyleft0, tyright = tyright0;
philpem@5 20646 if (xright<xleft) cimg::swap(xleft,xright,txleft,txright,tyleft,tyright);
philpem@5 20647 const int
philpem@5 20648 dx = xright - xleft,
philpem@5 20649 dtx = txright>txleft?txright - txleft:txleft - txright,
philpem@5 20650 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
philpem@5 20651 rtx = dx?(txright - txleft)/dx:0,
philpem@5 20652 rty = dx?(tyright - tyleft)/dx:0,
philpem@5 20653 stx = txright>txleft?1:-1,
philpem@5 20654 sty = tyright>tyleft?1:-1,
philpem@5 20655 ndtx = dtx - (dx?dx*(dtx/dx):0),
philpem@5 20656 ndty = dty - (dx?dx*(dty/dx):0);
philpem@5 20657 int errtx = dx>>1, errty = errtx;
philpem@5 20658 if (xleft<0 && dx) {
philpem@5 20659 txleft-=xleft*(txright - txleft)/dx;
philpem@5 20660 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 20661 }
philpem@5 20662 if (xleft<0) xleft = 0;
philpem@5 20663 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20664 T* ptrd = ptr(xleft,y,0,0);
philpem@5 20665 if (opacity>=1) {
philpem@5 20666 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20667 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20668 cimg_forV(*this,k) {
philpem@5 20669 *ptrd = (T)*col;
philpem@5 20670 ptrd+=whz; col+=twhz;
philpem@5 20671 }
philpem@5 20672 ptrd-=offx;
philpem@5 20673 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20674 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20675 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20676 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20677 cimg_forV(*this,k) {
philpem@5 20678 *ptrd = (T)(nbrightness**col);
philpem@5 20679 ptrd+=whz; col+=twhz;
philpem@5 20680 }
philpem@5 20681 ptrd-=offx;
philpem@5 20682 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20683 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20684 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 20685 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20686 cimg_forV(*this,k) {
philpem@5 20687 *ptrd = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
philpem@5 20688 ptrd+=whz; col+=twhz;
philpem@5 20689 }
philpem@5 20690 ptrd-=offx;
philpem@5 20691 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20692 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20693 }
philpem@5 20694 } else {
philpem@5 20695 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20696 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20697 cimg_forV(*this,k) {
philpem@5 20698 *ptrd = (T)(nopacity**col + *ptrd*copacity);
philpem@5 20699 ptrd+=whz; col+=twhz;
philpem@5 20700 }
philpem@5 20701 ptrd-=offx;
philpem@5 20702 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20703 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20704 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20705 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20706 cimg_forV(*this,k) {
philpem@5 20707 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
philpem@5 20708 ptrd+=whz; col+=twhz;
philpem@5 20709 }
philpem@5 20710 ptrd-=offx;
philpem@5 20711 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20712 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20713 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 20714 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 20715 cimg_forV(*this,k) {
philpem@5 20716 const T val = (T)((2-nbrightness)**(col++) + (nbrightness-1)*maxval);
philpem@5 20717 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20718 ptrd+=whz; col+=twhz;
philpem@5 20719 }
philpem@5 20720 ptrd-=offx;
philpem@5 20721 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 20722 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 20723 }
philpem@5 20724 }
philpem@5 20725 }
philpem@5 20726 return *this;
philpem@5 20727 }
philpem@5 20728
philpem@5 20729 //! Draw a 2D textured triangle, with perspective correction.
philpem@5 20730 template<typename tc>
philpem@5 20731 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
philpem@5 20732 const int x1, const int y1, const float z1,
philpem@5 20733 const int x2, const int y2, const float z2,
philpem@5 20734 const CImg<tc>& texture,
philpem@5 20735 const int tx0, const int ty0,
philpem@5 20736 const int tx1, const int ty1,
philpem@5 20737 const int tx2, const int ty2,
philpem@5 20738 const float opacity=1,
philpem@5 20739 const float brightness=1) {
philpem@5 20740 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 20741 if (!texture || texture.dim<dim)
philpem@5 20742 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 20743 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 20744 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
philpem@5 20745 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20746 const float
philpem@5 20747 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
philpem@5 20748 nbrightness = brightness<0?0:(brightness>2?2:brightness);
philpem@5 20749 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 20750 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
philpem@5 20751 float
philpem@5 20752 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 20753 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 20754 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 20755 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 20756 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
philpem@5 20757 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
philpem@5 20758 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
philpem@5 20759 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20760 float
philpem@5 20761 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 20762 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 20763 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 20764 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 20765 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 20766 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 20767 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 20768 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 20769 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 20770 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 20771 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 20772 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 20773 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 20774 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 20775 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 20776 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
philpem@5 20777 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 20778 int xleft = xleft0, xright = xright0;
philpem@5 20779 float
philpem@5 20780 zleft = zl, zright = zr,
philpem@5 20781 txleft = txl, txright = txr,
philpem@5 20782 tyleft = tyl, tyright = tyr;
philpem@5 20783 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
philpem@5 20784 const int dx = xright - xleft;
philpem@5 20785 const float
philpem@5 20786 pentez = (zright - zleft)/dx,
philpem@5 20787 pentetx = (txright - txleft)/dx,
philpem@5 20788 pentety = (tyright - tyleft)/dx;
philpem@5 20789 if (xleft<0 && dx) {
philpem@5 20790 zleft-=xleft*(zright - zleft)/dx;
philpem@5 20791 txleft-=xleft*(txright - txleft)/dx;
philpem@5 20792 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 20793 }
philpem@5 20794 if (xleft<0) xleft = 0;
philpem@5 20795 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20796 T* ptrd = ptr(xleft,y,0,0);
philpem@5 20797 if (opacity>=1) {
philpem@5 20798 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20799 const float invz = 1/zleft;
philpem@5 20800 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20801 cimg_forV(*this,k) {
philpem@5 20802 *ptrd = (T)*col;
philpem@5 20803 ptrd+=whz; col+=twhz;
philpem@5 20804 }
philpem@5 20805 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20806 } else if (nbrightness<1) for (int x=xleft; x<=xright; ++x) {
philpem@5 20807 const float invz = 1/zleft;
philpem@5 20808 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20809 cimg_forV(*this,k) {
philpem@5 20810 *ptrd = (T)(nbrightness**col);
philpem@5 20811 ptrd+=whz; col+=twhz;
philpem@5 20812 }
philpem@5 20813 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20814 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 20815 const float invz = 1/zleft;
philpem@5 20816 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20817 cimg_forV(*this,k) {
philpem@5 20818 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
philpem@5 20819 ptrd+=whz; col+=twhz;
philpem@5 20820 }
philpem@5 20821 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20822 }
philpem@5 20823 } else {
philpem@5 20824 if (nbrightness==1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20825 const float invz = 1/zleft;
philpem@5 20826 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20827 cimg_forV(*this,k) {
philpem@5 20828 *ptrd = (T)(nopacity**col + *ptrd*copacity);
philpem@5 20829 ptrd+=whz; col+=twhz;
philpem@5 20830 }
philpem@5 20831 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20832 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x) {
philpem@5 20833 const float invz = 1/zleft;
philpem@5 20834 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20835 cimg_forV(*this,k) {
philpem@5 20836 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
philpem@5 20837 ptrd+=whz; col+=twhz;
philpem@5 20838 }
philpem@5 20839 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20840 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 20841 const float invz = 1/zleft;
philpem@5 20842 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20843 cimg_forV(*this,k) {
philpem@5 20844 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
philpem@5 20845 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20846 ptrd+=whz; col+=twhz;
philpem@5 20847 }
philpem@5 20848 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20849 }
philpem@5 20850 }
philpem@5 20851 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 20852 }
philpem@5 20853 return *this;
philpem@5 20854 }
philpem@5 20855
philpem@5 20856 //! Draw a 2D textured triangle, with z-buffering and perspective correction.
philpem@5 20857 template<typename tc>
philpem@5 20858 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 20859 const int x0, const int y0, const float z0,
philpem@5 20860 const int x1, const int y1, const float z1,
philpem@5 20861 const int x2, const int y2, const float z2,
philpem@5 20862 const CImg<tc>& texture,
philpem@5 20863 const int tx0, const int ty0,
philpem@5 20864 const int tx1, const int ty1,
philpem@5 20865 const int tx2, const int ty2,
philpem@5 20866 const float opacity=1,
philpem@5 20867 const float brightness=1) {
philpem@5 20868 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 20869 if (!texture || texture.dim<dim)
philpem@5 20870 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 20871 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 20872 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness);
philpem@5 20873 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 20874 const float
philpem@5 20875 nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0),
philpem@5 20876 nbrightness = brightness<0?0:(brightness>2?2:brightness);
philpem@5 20877 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
philpem@5 20878 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2;
philpem@5 20879 float
philpem@5 20880 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 20881 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 20882 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 20883 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 20884 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1);
philpem@5 20885 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2);
philpem@5 20886 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2);
philpem@5 20887 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 20888 float
philpem@5 20889 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 20890 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 20891 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 20892 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 20893 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 20894 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 20895 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 20896 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 20897 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 20898 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 20899 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 20900 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 20901 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 20902 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 20903 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 20904 _cimg_for_triangle1(*this,xleft0,xright0,y,nx0,ny0,nx1,ny1,nx2,ny2) {
philpem@5 20905 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 20906 int xleft = xleft0, xright = xright0;
philpem@5 20907 float
philpem@5 20908 zleft = zl, zright = zr,
philpem@5 20909 txleft = txl, txright = txr,
philpem@5 20910 tyleft = tyl, tyright = tyr;
philpem@5 20911 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright);
philpem@5 20912 const int dx = xright - xleft;
philpem@5 20913 const float
philpem@5 20914 pentez = (zright - zleft)/dx,
philpem@5 20915 pentetx = (txright - txleft)/dx,
philpem@5 20916 pentety = (tyright - tyleft)/dx;
philpem@5 20917 if (xleft<0 && dx) {
philpem@5 20918 zleft-=xleft*(zright - zleft)/dx;
philpem@5 20919 txleft-=xleft*(txright - txleft)/dx;
philpem@5 20920 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 20921 }
philpem@5 20922 if (xleft<0) xleft = 0;
philpem@5 20923 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 20924 T *ptrd = ptr(xleft,y,0,0);
philpem@5 20925 float *ptrz = zbuffer + xleft + y*width;
philpem@5 20926 if (opacity>=1) {
philpem@5 20927 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20928 if (zleft>*ptrz) {
philpem@5 20929 *ptrz = zleft;
philpem@5 20930 const float invz = 1/zleft;
philpem@5 20931 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20932 cimg_forV(*this,k) {
philpem@5 20933 *ptrd = (T)*col;
philpem@5 20934 ptrd+=whz; col+=twhz;
philpem@5 20935 }
philpem@5 20936 ptrd-=offx;
philpem@5 20937 }
philpem@5 20938 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20939 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20940 if (zleft>*ptrz) {
philpem@5 20941 *ptrz = zleft;
philpem@5 20942 const float invz = 1/zleft;
philpem@5 20943 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20944 cimg_forV(*this,k) {
philpem@5 20945 *ptrd = (T)(nbrightness**col);
philpem@5 20946 ptrd+=whz; col+=twhz;
philpem@5 20947 }
philpem@5 20948 ptrd-=offx;
philpem@5 20949 }
philpem@5 20950 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20951 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20952 if (zleft>*ptrz) {
philpem@5 20953 *ptrz = zleft;
philpem@5 20954 const float invz = 1/zleft;
philpem@5 20955 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20956 cimg_forV(*this,k) {
philpem@5 20957 *ptrd = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
philpem@5 20958 ptrd+=whz; col+=twhz;
philpem@5 20959 }
philpem@5 20960 ptrd-=offx;
philpem@5 20961 }
philpem@5 20962 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20963 }
philpem@5 20964 } else {
philpem@5 20965 if (nbrightness==1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20966 if (zleft>*ptrz) {
philpem@5 20967 *ptrz = zleft;
philpem@5 20968 const float invz = 1/zleft;
philpem@5 20969 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20970 cimg_forV(*this,k) {
philpem@5 20971 *ptrd = (T)(nopacity**col + *ptrd*copacity);
philpem@5 20972 ptrd+=whz; col+=twhz;
philpem@5 20973 }
philpem@5 20974 ptrd-=offx;
philpem@5 20975 }
philpem@5 20976 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20977 } else if (nbrightness<1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20978 if (zleft>*ptrz) {
philpem@5 20979 *ptrz = zleft;
philpem@5 20980 const float invz = 1/zleft;
philpem@5 20981 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20982 cimg_forV(*this,k) {
philpem@5 20983 *ptrd = (T)(nopacity*nbrightness**col + *ptrd*copacity);
philpem@5 20984 ptrd+=whz; col+=twhz;
philpem@5 20985 }
philpem@5 20986 ptrd-=offx;
philpem@5 20987 }
philpem@5 20988 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 20989 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 20990 if (zleft>*ptrz) {
philpem@5 20991 *ptrz = zleft;
philpem@5 20992 const float invz = 1/zleft;
philpem@5 20993 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 20994 cimg_forV(*this,k) {
philpem@5 20995 const T val = (T)((2-nbrightness)**col + (nbrightness-1)*maxval);
philpem@5 20996 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 20997 ptrd+=whz; col+=twhz;
philpem@5 20998 }
philpem@5 20999 ptrd-=offx;
philpem@5 21000 }
philpem@5 21001 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21002 }
philpem@5 21003 }
philpem@5 21004 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 21005 }
philpem@5 21006 return *this;
philpem@5 21007 }
philpem@5 21008
philpem@5 21009 //! Draw a 2D Pseudo-Phong-shaded triangle.
philpem@5 21010 /**
philpem@5 21011 \param x0 = X-coordinate of the first corner in the instance image.
philpem@5 21012 \param y0 = Y-coordinate of the first corner in the instance image.
philpem@5 21013 \param x1 = X-coordinate of the second corner in the instance image.
philpem@5 21014 \param y1 = Y-coordinate of the second corner in the instance image.
philpem@5 21015 \param x2 = X-coordinate of the third corner in the instance image.
philpem@5 21016 \param y2 = Y-coordinate of the third corner in the instance image.
philpem@5 21017 \param color = array of dimv() values of type \c T, defining the global drawing color.
philpem@5 21018 \param light = light image.
philpem@5 21019 \param lx0 = X-coordinate of the first corner in the light image.
philpem@5 21020 \param ly0 = Y-coordinate of the first corner in the light image.
philpem@5 21021 \param lx1 = X-coordinate of the second corner in the light image.
philpem@5 21022 \param ly1 = Y-coordinate of the second corner in the light image.
philpem@5 21023 \param lx2 = X-coordinate of the third corner in the light image.
philpem@5 21024 \param ly2 = Y-coordinate of the third corner in the light image.
philpem@5 21025 \param opacity = opacity of the drawing.
philpem@5 21026 \note Clipping is supported, but texture coordinates do not support clipping.
philpem@5 21027 **/
philpem@5 21028 template<typename tc, typename tl>
philpem@5 21029 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 21030 const int x1, const int y1,
philpem@5 21031 const int x2, const int y2,
philpem@5 21032 const tc *const color,
philpem@5 21033 const CImg<tl>& light,
philpem@5 21034 const int lx0, const int ly0,
philpem@5 21035 const int lx1, const int ly1,
philpem@5 21036 const int lx2, const int ly2,
philpem@5 21037 const float opacity=1) {
philpem@5 21038 if (is_empty()) return *this;
philpem@5 21039 if (!color)
philpem@5 21040 throw CImgArgumentException("CImg<%s>::draw_triangle : Specified color is (null).",
philpem@5 21041 pixel_type());
philpem@5 21042 if (!light)
philpem@5 21043 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
philpem@5 21044 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
philpem@5 21045 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,color,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21046 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21047 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21048 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21049 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
philpem@5 21050 const int whz = width*height*depth, offx = dim*whz-1;
philpem@5 21051 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1);
philpem@5 21052 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2);
philpem@5 21053 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2);
philpem@5 21054 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21055 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
philpem@5 21056 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
philpem@5 21057 int
philpem@5 21058 xleft = xleft0, xright = xright0,
philpem@5 21059 lxleft = lxleft0, lxright = lxright0,
philpem@5 21060 lyleft = lyleft0, lyright = lyright0;
philpem@5 21061 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright);
philpem@5 21062 const int
philpem@5 21063 dx = xright - xleft,
philpem@5 21064 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
philpem@5 21065 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
philpem@5 21066 rlx = dx?(lxright - lxleft)/dx:0,
philpem@5 21067 rly = dx?(lyright - lyleft)/dx:0,
philpem@5 21068 slx = lxright>lxleft?1:-1,
philpem@5 21069 sly = lyright>lyleft?1:-1,
philpem@5 21070 ndlx = dlx - (dx?dx*(dlx/dx):0),
philpem@5 21071 ndly = dly - (dx?dx*(dly/dx):0);
philpem@5 21072 int errlx = dx>>1, errly = errlx;
philpem@5 21073 if (xleft<0 && dx) {
philpem@5 21074 lxleft-=xleft*(lxright - lxleft)/dx;
philpem@5 21075 lyleft-=xleft*(lyright - lyleft)/dx;
philpem@5 21076 }
philpem@5 21077 if (xleft<0) xleft = 0;
philpem@5 21078 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21079 T* ptrd = ptr(xleft,y,0,0);
philpem@5 21080 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 21081 const tl l = light(lxleft,lyleft);
philpem@5 21082 const tc *col = color;
philpem@5 21083 cimg_forV(*this,k) {
philpem@5 21084 *ptrd = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
philpem@5 21085 ptrd+=whz;
philpem@5 21086 }
philpem@5 21087 ptrd-=offx;
philpem@5 21088 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21089 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21090 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 21091 const tl l = light(lxleft,lyleft);
philpem@5 21092 const tc *col = color;
philpem@5 21093 cimg_forV(*this,k) {
philpem@5 21094 const T val = (T)(l<1?l**(col++):((2-l)**(col++)+(l-1)*maxval));
philpem@5 21095 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21096 ptrd+=whz;
philpem@5 21097 }
philpem@5 21098 ptrd-=offx;
philpem@5 21099 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21100 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21101 }
philpem@5 21102 }
philpem@5 21103 return *this;
philpem@5 21104 }
philpem@5 21105
philpem@5 21106 //! Draw a 2D Pseudo-Phong-shaded triangle.
philpem@5 21107 template<typename tc, typename tl>
philpem@5 21108 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 21109 const int x1, const int y1,
philpem@5 21110 const int x2, const int y2,
philpem@5 21111 const CImg<tc>& color,
philpem@5 21112 const CImg<tl>& light,
philpem@5 21113 const int lx0, const int ly0,
philpem@5 21114 const int lx1, const int ly1,
philpem@5 21115 const int lx2, const int ly2,
philpem@5 21116 const float opacity=1) {
philpem@5 21117 return draw_triangle(x0,y0,x1,y1,x2,y2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21118 }
philpem@5 21119
philpem@5 21120 //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
philpem@5 21121 template<typename tc, typename tl>
philpem@5 21122 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 21123 const int x0, const int y0, const float z0,
philpem@5 21124 const int x1, const int y1, const float z1,
philpem@5 21125 const int x2, const int y2, const float z2,
philpem@5 21126 const tc *const color,
philpem@5 21127 const CImg<tl>& light,
philpem@5 21128 const int lx0, const int ly0,
philpem@5 21129 const int lx1, const int ly1,
philpem@5 21130 const int lx2, const int ly2,
philpem@5 21131 const float opacity=1) {
philpem@5 21132 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 21133 if (!color)
philpem@5 21134 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified color is (null).",
philpem@5 21135 pixel_type());
philpem@5 21136 if (!light)
philpem@5 21137 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
philpem@5 21138 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
philpem@5 21139 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,
philpem@5 21140 +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21141 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21142 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21143 const int whz = width*height*depth, offx = dim*whz;
philpem@5 21144 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21145 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
philpem@5 21146 float nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 21147 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1,nz0,nz1);
philpem@5 21148 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2,nz0,nz2);
philpem@5 21149 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2,nz1,nz2);
philpem@5 21150 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21151 float
philpem@5 21152 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 21153 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 21154 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 21155 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 21156 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1)));
philpem@5 21157 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
philpem@5 21158 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
philpem@5 21159 if (y==ny1) { zl = nz1; pzl = pzn; }
philpem@5 21160 int
philpem@5 21161 xleft = xleft0, xright = xright0,
philpem@5 21162 lxleft = lxleft0, lxright = lxright0,
philpem@5 21163 lyleft = lyleft0, lyright = lyright0;
philpem@5 21164 float zleft = zl, zright = zr;
philpem@5 21165 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,lxleft,lxright,lyleft,lyright);
philpem@5 21166 const int
philpem@5 21167 dx = xright - xleft,
philpem@5 21168 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
philpem@5 21169 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
philpem@5 21170 rlx = dx?(lxright - lxleft)/dx:0,
philpem@5 21171 rly = dx?(lyright - lyleft)/dx:0,
philpem@5 21172 slx = lxright>lxleft?1:-1,
philpem@5 21173 sly = lyright>lyleft?1:-1,
philpem@5 21174 ndlx = dlx - (dx?dx*(dlx/dx):0),
philpem@5 21175 ndly = dly - (dx?dx*(dly/dx):0);
philpem@5 21176 const float pentez = (zright - zleft)/dx;
philpem@5 21177 int errlx = dx>>1, errly = errlx;
philpem@5 21178 if (xleft<0 && dx) {
philpem@5 21179 zleft-=xleft*(zright - zleft)/dx;
philpem@5 21180 lxleft-=xleft*(lxright - lxleft)/dx;
philpem@5 21181 lyleft-=xleft*(lyright - lyleft)/dx;
philpem@5 21182 }
philpem@5 21183 if (xleft<0) xleft = 0;
philpem@5 21184 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21185 T *ptrd = ptr(xleft,y,0,0);
philpem@5 21186 float *ptrz = zbuffer + xleft + y*width;
philpem@5 21187 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 21188 if (zleft>*ptrz) {
philpem@5 21189 *ptrz = zleft;
philpem@5 21190 const tl l = light(lxleft,lyleft);
philpem@5 21191 const tc *col = color;
philpem@5 21192 cimg_forV(*this,k) {
philpem@5 21193 const tc cval = *(col++);
philpem@5 21194 *ptrd = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
philpem@5 21195 ptrd+=whz;
philpem@5 21196 }
philpem@5 21197 ptrd-=offx;
philpem@5 21198 }
philpem@5 21199 zleft+=pentez;
philpem@5 21200 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21201 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21202 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 21203 if (zleft>*ptrz) {
philpem@5 21204 *ptrz = zleft;
philpem@5 21205 const tl l = light(lxleft,lyleft);
philpem@5 21206 const tc *col = color;
philpem@5 21207 cimg_forV(*this,k) {
philpem@5 21208 const tc cval = *(col++);
philpem@5 21209 const T val = (T)(l<1?l*cval:(2-l)*cval+(l-1)*maxval);
philpem@5 21210 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21211 ptrd+=whz;
philpem@5 21212 }
philpem@5 21213 ptrd-=offx;
philpem@5 21214 }
philpem@5 21215 zleft+=pentez;
philpem@5 21216 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21217 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21218 }
philpem@5 21219 zr+=pzr; zl+=pzl;
philpem@5 21220 }
philpem@5 21221 return *this;
philpem@5 21222 }
philpem@5 21223
philpem@5 21224 //! Draw a 2D Pseudo-Phong-shaded triangle, with z-buffering.
philpem@5 21225 template<typename tc, typename tl>
philpem@5 21226 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 21227 const int x0, const int y0, const float z0,
philpem@5 21228 const int x1, const int y1, const float z1,
philpem@5 21229 const int x2, const int y2, const float z2,
philpem@5 21230 const CImg<tc>& color,
philpem@5 21231 const CImg<tl>& light,
philpem@5 21232 const int lx0, const int ly0,
philpem@5 21233 const int lx1, const int ly1,
philpem@5 21234 const int lx2, const int ly2,
philpem@5 21235 const float opacity=1) {
philpem@5 21236 return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21237 }
philpem@5 21238
philpem@5 21239 //! Draw a 2D Gouraud-shaded textured triangle.
philpem@5 21240 /**
philpem@5 21241 \param x0 = X-coordinate of the first corner in the instance image.
philpem@5 21242 \param y0 = Y-coordinate of the first corner in the instance image.
philpem@5 21243 \param x1 = X-coordinate of the second corner in the instance image.
philpem@5 21244 \param y1 = Y-coordinate of the second corner in the instance image.
philpem@5 21245 \param x2 = X-coordinate of the third corner in the instance image.
philpem@5 21246 \param y2 = Y-coordinate of the third corner in the instance image.
philpem@5 21247 \param texture = texture image used to fill the triangle.
philpem@5 21248 \param tx0 = X-coordinate of the first corner in the texture image.
philpem@5 21249 \param ty0 = Y-coordinate of the first corner in the texture image.
philpem@5 21250 \param tx1 = X-coordinate of the second corner in the texture image.
philpem@5 21251 \param ty1 = Y-coordinate of the second corner in the texture image.
philpem@5 21252 \param tx2 = X-coordinate of the third corner in the texture image.
philpem@5 21253 \param ty2 = Y-coordinate of the third corner in the texture image.
philpem@5 21254 \param brightness0 = brightness value of the first corner.
philpem@5 21255 \param brightness1 = brightness value of the second corner.
philpem@5 21256 \param brightness2 = brightness value of the third corner.
philpem@5 21257 \param opacity = opacity of the drawing.
philpem@5 21258 \note Clipping is supported, but texture coordinates do not support clipping.
philpem@5 21259 **/
philpem@5 21260 template<typename tc>
philpem@5 21261 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 21262 const int x1, const int y1,
philpem@5 21263 const int x2, const int y2,
philpem@5 21264 const CImg<tc>& texture,
philpem@5 21265 const int tx0, const int ty0,
philpem@5 21266 const int tx1, const int ty1,
philpem@5 21267 const int tx2, const int ty2,
philpem@5 21268 const float brightness0,
philpem@5 21269 const float brightness1,
philpem@5 21270 const float brightness2,
philpem@5 21271 const float opacity=1) {
philpem@5 21272 if (is_empty()) return *this;
philpem@5 21273 if (!texture || texture.dim<dim)
philpem@5 21274 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21275 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21276 if (is_overlapped(texture))
philpem@5 21277 return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,brightness0,brightness1,brightness2,opacity);
philpem@5 21278 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21279 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21280 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 21281 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21282 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
philpem@5 21283 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
philpem@5 21284 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
philpem@5 21285 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
philpem@5 21286 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1);
philpem@5 21287 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2);
philpem@5 21288 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2);
philpem@5 21289 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21290 _cimg_for_triangle4(*this,xleft0,cleft0,txleft0,tyleft0,xright0,cright0,txright0,tyright0,y,
philpem@5 21291 nx0,ny0,nc0,ntx0,nty0,nx1,ny1,nc1,ntx1,nty1,nx2,ny2,nc2,ntx2,nty2) {
philpem@5 21292 int
philpem@5 21293 xleft = xleft0, xright = xright0,
philpem@5 21294 cleft = cleft0, cright = cright0,
philpem@5 21295 txleft = txleft0, txright = txright0,
philpem@5 21296 tyleft = tyleft0, tyright = tyright0;
philpem@5 21297 if (xright<xleft) cimg::swap(xleft,xright,cleft,cright,txleft,txright,tyleft,tyright);
philpem@5 21298 const int
philpem@5 21299 dx = xright - xleft,
philpem@5 21300 dc = cright>cleft?cright - cleft:cleft - cright,
philpem@5 21301 dtx = txright>txleft?txright - txleft:txleft - txright,
philpem@5 21302 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
philpem@5 21303 rc = dx?(cright - cleft)/dx:0,
philpem@5 21304 rtx = dx?(txright - txleft)/dx:0,
philpem@5 21305 rty = dx?(tyright - tyleft)/dx:0,
philpem@5 21306 sc = cright>cleft?1:-1,
philpem@5 21307 stx = txright>txleft?1:-1,
philpem@5 21308 sty = tyright>tyleft?1:-1,
philpem@5 21309 ndc = dc - (dx?dx*(dc/dx):0),
philpem@5 21310 ndtx = dtx - (dx?dx*(dtx/dx):0),
philpem@5 21311 ndty = dty - (dx?dx*(dty/dx):0);
philpem@5 21312 int errc = dx>>1, errtx = errc, errty = errc;
philpem@5 21313 if (xleft<0 && dx) {
philpem@5 21314 cleft-=xleft*(cright - cleft)/dx;
philpem@5 21315 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21316 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21317 }
philpem@5 21318 if (xleft<0) xleft = 0;
philpem@5 21319 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21320 T* ptrd = ptr(xleft,y,0,0);
philpem@5 21321 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 21322 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 21323 cimg_forV(*this,k) {
philpem@5 21324 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21325 ptrd+=whz; col+=twhz;
philpem@5 21326 }
philpem@5 21327 ptrd-=offx;
philpem@5 21328 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21329 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 21330 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 21331 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 21332 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 21333 cimg_forV(*this,k) {
philpem@5 21334 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21335 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21336 ptrd+=whz; col+=twhz;
philpem@5 21337 }
philpem@5 21338 ptrd-=offx;
philpem@5 21339 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21340 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 21341 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 21342 }
philpem@5 21343 }
philpem@5 21344 return *this;
philpem@5 21345 }
philpem@5 21346
philpem@5 21347 //! Draw a 2D Gouraud-shaded textured triangle, with perspective correction.
philpem@5 21348 template<typename tc>
philpem@5 21349 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
philpem@5 21350 const int x1, const int y1, const float z1,
philpem@5 21351 const int x2, const int y2, const float z2,
philpem@5 21352 const CImg<tc>& texture,
philpem@5 21353 const int tx0, const int ty0,
philpem@5 21354 const int tx1, const int ty1,
philpem@5 21355 const int tx2, const int ty2,
philpem@5 21356 const float brightness0,
philpem@5 21357 const float brightness1,
philpem@5 21358 const float brightness2,
philpem@5 21359 const float opacity=1) {
philpem@5 21360 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 21361 if (!texture || texture.dim<dim)
philpem@5 21362 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21363 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21364 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
philpem@5 21365 brightness0,brightness1,brightness2,opacity);
philpem@5 21366 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21367 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21368 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 21369 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21370 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
philpem@5 21371 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
philpem@5 21372 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
philpem@5 21373 float
philpem@5 21374 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 21375 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 21376 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 21377 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 21378 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
philpem@5 21379 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
philpem@5 21380 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
philpem@5 21381 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21382 float
philpem@5 21383 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 21384 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 21385 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 21386 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 21387 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 21388 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 21389 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 21390 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 21391 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 21392 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 21393 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 21394 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 21395 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 21396 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 21397 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 21398 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
philpem@5 21399 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 21400 int
philpem@5 21401 xleft = xleft0, xright = xright0,
philpem@5 21402 cleft = cleft0, cright = cright0;
philpem@5 21403 float
philpem@5 21404 zleft = zl, zright = zr,
philpem@5 21405 txleft = txl, txright = txr,
philpem@5 21406 tyleft = tyl, tyright = tyr;
philpem@5 21407 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
philpem@5 21408 const int
philpem@5 21409 dx = xright - xleft,
philpem@5 21410 dc = cright>cleft?cright - cleft:cleft - cright,
philpem@5 21411 rc = dx?(cright - cleft)/dx:0,
philpem@5 21412 sc = cright>cleft?1:-1,
philpem@5 21413 ndc = dc - (dx?dx*(dc/dx):0);
philpem@5 21414 const float
philpem@5 21415 pentez = (zright - zleft)/dx,
philpem@5 21416 pentetx = (txright - txleft)/dx,
philpem@5 21417 pentety = (tyright - tyleft)/dx;
philpem@5 21418 int errc = dx>>1;
philpem@5 21419 if (xleft<0 && dx) {
philpem@5 21420 cleft-=xleft*(cright - cleft)/dx;
philpem@5 21421 zleft-=xleft*(zright - zleft)/dx;
philpem@5 21422 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21423 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21424 }
philpem@5 21425 if (xleft<0) xleft = 0;
philpem@5 21426 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21427 T* ptrd = ptr(xleft,y,0,0);
philpem@5 21428 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 21429 const float invz = 1/zleft;
philpem@5 21430 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21431 cimg_forV(*this,k) {
philpem@5 21432 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21433 ptrd+=whz; col+=twhz;
philpem@5 21434 }
philpem@5 21435 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21436 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21437 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 21438 const float invz = 1/zleft;
philpem@5 21439 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21440 cimg_forV(*this,k) {
philpem@5 21441 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21442 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21443 ptrd+=whz; col+=twhz;
philpem@5 21444 }
philpem@5 21445 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21446 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21447 }
philpem@5 21448 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 21449 }
philpem@5 21450 return *this;
philpem@5 21451 }
philpem@5 21452
philpem@5 21453 //! Draw a 2D Gouraud-shaded textured triangle, with z-buffering and perspective correction.
philpem@5 21454 template<typename tc>
philpem@5 21455 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 21456 const int x0, const int y0, const float z0,
philpem@5 21457 const int x1, const int y1, const float z1,
philpem@5 21458 const int x2, const int y2, const float z2,
philpem@5 21459 const CImg<tc>& texture,
philpem@5 21460 const int tx0, const int ty0,
philpem@5 21461 const int tx1, const int ty1,
philpem@5 21462 const int tx2, const int ty2,
philpem@5 21463 const float brightness0,
philpem@5 21464 const float brightness1,
philpem@5 21465 const float brightness2,
philpem@5 21466 const float opacity=1) {
philpem@5 21467 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 21468 if (!texture || texture.dim<dim)
philpem@5 21469 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21470 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21471 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,
philpem@5 21472 brightness0,brightness1,brightness2,opacity);
philpem@5 21473 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21474 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21475 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
philpem@5 21476 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21477 nc0 = (int)((brightness0<0?0:(brightness0>2?2:brightness0))*256),
philpem@5 21478 nc1 = (int)((brightness1<0?0:(brightness1>2?2:brightness1))*256),
philpem@5 21479 nc2 = (int)((brightness2<0?0:(brightness2>2?2:brightness2))*256);
philpem@5 21480 float
philpem@5 21481 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 21482 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 21483 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 21484 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 21485 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nz0,nz1,nc0,nc1);
philpem@5 21486 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nz0,nz2,nc0,nc2);
philpem@5 21487 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nz1,nz2,nc1,nc2);
philpem@5 21488 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21489 float
philpem@5 21490 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 21491 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 21492 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 21493 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 21494 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 21495 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 21496 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 21497 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 21498 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 21499 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 21500 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 21501 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 21502 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 21503 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 21504 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 21505 _cimg_for_triangle2(*this,xleft0,cleft0,xright0,cright0,y,nx0,ny0,nc0,nx1,ny1,nc1,nx2,ny2,nc2) {
philpem@5 21506 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 21507 int
philpem@5 21508 xleft = xleft0, xright = xright0,
philpem@5 21509 cleft = cleft0, cright = cright0;
philpem@5 21510 float
philpem@5 21511 zleft = zl, zright = zr,
philpem@5 21512 txleft = txl, txright = txr,
philpem@5 21513 tyleft = tyl, tyright = tyr;
philpem@5 21514 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,cleft,cright);
philpem@5 21515 const int
philpem@5 21516 dx = xright - xleft,
philpem@5 21517 dc = cright>cleft?cright - cleft:cleft - cright,
philpem@5 21518 rc = dx?(cright - cleft)/dx:0,
philpem@5 21519 sc = cright>cleft?1:-1,
philpem@5 21520 ndc = dc - (dx?dx*(dc/dx):0);
philpem@5 21521 const float
philpem@5 21522 pentez = (zright - zleft)/dx,
philpem@5 21523 pentetx = (txright - txleft)/dx,
philpem@5 21524 pentety = (tyright - tyleft)/dx;
philpem@5 21525 int errc = dx>>1;
philpem@5 21526 if (xleft<0 && dx) {
philpem@5 21527 cleft-=xleft*(cright - cleft)/dx;
philpem@5 21528 zleft-=xleft*(zright - zleft)/dx;
philpem@5 21529 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21530 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21531 }
philpem@5 21532 if (xleft<0) xleft = 0;
philpem@5 21533 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21534 T* ptrd = ptr(xleft,y);
philpem@5 21535 float *ptrz = zbuffer + xleft + y*width;
philpem@5 21536 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
philpem@5 21537 if (zleft>*ptrz) {
philpem@5 21538 *ptrz = zleft;
philpem@5 21539 const float invz = 1/zleft;
philpem@5 21540 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21541 cimg_forV(*this,k) {
philpem@5 21542 *ptrd = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21543 ptrd+=whz; col+=twhz;
philpem@5 21544 }
philpem@5 21545 ptrd-=offx;
philpem@5 21546 }
philpem@5 21547 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21548 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21549 } else for (int x = xleft; x<=xright; ++x, ++ptrd, ++ptrz) {
philpem@5 21550 if (zleft>*ptrz) {
philpem@5 21551 *ptrz = zleft;
philpem@5 21552 const float invz = 1/zleft;
philpem@5 21553 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21554 cimg_forV(*this,k) {
philpem@5 21555 const T val = (T)(cleft<256?cleft**col/256:((512-cleft)**col+(cleft-256)*maxval)/256);
philpem@5 21556 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21557 ptrd+=whz; col+=twhz;
philpem@5 21558 }
philpem@5 21559 ptrd-=offx;
philpem@5 21560 }
philpem@5 21561 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21562 cleft+=rc+((errc-=ndc)<0?errc+=dx,sc:0);
philpem@5 21563 }
philpem@5 21564 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 21565 }
philpem@5 21566 return *this;
philpem@5 21567 }
philpem@5 21568
philpem@5 21569 //! Draw a 2D Pseudo-Phong-shaded textured triangle.
philpem@5 21570 /**
philpem@5 21571 \param x0 = X-coordinate of the first corner in the instance image.
philpem@5 21572 \param y0 = Y-coordinate of the first corner in the instance image.
philpem@5 21573 \param x1 = X-coordinate of the second corner in the instance image.
philpem@5 21574 \param y1 = Y-coordinate of the second corner in the instance image.
philpem@5 21575 \param x2 = X-coordinate of the third corner in the instance image.
philpem@5 21576 \param y2 = Y-coordinate of the third corner in the instance image.
philpem@5 21577 \param texture = texture image used to fill the triangle.
philpem@5 21578 \param tx0 = X-coordinate of the first corner in the texture image.
philpem@5 21579 \param ty0 = Y-coordinate of the first corner in the texture image.
philpem@5 21580 \param tx1 = X-coordinate of the second corner in the texture image.
philpem@5 21581 \param ty1 = Y-coordinate of the second corner in the texture image.
philpem@5 21582 \param tx2 = X-coordinate of the third corner in the texture image.
philpem@5 21583 \param ty2 = Y-coordinate of the third corner in the texture image.
philpem@5 21584 \param light = light image.
philpem@5 21585 \param lx0 = X-coordinate of the first corner in the light image.
philpem@5 21586 \param ly0 = Y-coordinate of the first corner in the light image.
philpem@5 21587 \param lx1 = X-coordinate of the second corner in the light image.
philpem@5 21588 \param ly1 = Y-coordinate of the second corner in the light image.
philpem@5 21589 \param lx2 = X-coordinate of the third corner in the light image.
philpem@5 21590 \param ly2 = Y-coordinate of the third corner in the light image.
philpem@5 21591 \param opacity = opacity of the drawing.
philpem@5 21592 \note Clipping is supported, but texture coordinates do not support clipping.
philpem@5 21593 **/
philpem@5 21594 template<typename tc, typename tl>
philpem@5 21595 CImg<T>& draw_triangle(const int x0, const int y0,
philpem@5 21596 const int x1, const int y1,
philpem@5 21597 const int x2, const int y2,
philpem@5 21598 const CImg<tc>& texture,
philpem@5 21599 const int tx0, const int ty0,
philpem@5 21600 const int tx1, const int ty1,
philpem@5 21601 const int tx2, const int ty2,
philpem@5 21602 const CImg<tl>& light,
philpem@5 21603 const int lx0, const int ly0,
philpem@5 21604 const int lx1, const int ly1,
philpem@5 21605 const int lx2, const int ly2,
philpem@5 21606 const float opacity=1) {
philpem@5 21607 if (is_empty()) return *this;
philpem@5 21608 if (!texture || texture.dim<dim)
philpem@5 21609 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21610 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21611 if (!light)
philpem@5 21612 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
philpem@5 21613 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
philpem@5 21614 if (is_overlapped(texture)) return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21615 if (is_overlapped(light)) return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21616 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21617 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21618 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 21619 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21620 ntx0 = tx0, nty0 = ty0, ntx1 = tx1, nty1 = ty1, ntx2 = tx2, nty2 = ty2,
philpem@5 21621 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
philpem@5 21622 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1);
philpem@5 21623 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2);
philpem@5 21624 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2);
philpem@5 21625 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21626 _cimg_for_triangle5(*this,xleft0,lxleft0,lyleft0,txleft0,tyleft0,xright0,lxright0,lyright0,txright0,tyright0,y,
philpem@5 21627 nx0,ny0,nlx0,nly0,ntx0,nty0,nx1,ny1,nlx1,nly1,ntx1,nty1,nx2,ny2,nlx2,nly2,ntx2,nty2) {
philpem@5 21628 int
philpem@5 21629 xleft = xleft0, xright = xright0,
philpem@5 21630 lxleft = lxleft0, lxright = lxright0,
philpem@5 21631 lyleft = lyleft0, lyright = lyright0,
philpem@5 21632 txleft = txleft0, txright = txright0,
philpem@5 21633 tyleft = tyleft0, tyright = tyright0;
philpem@5 21634 if (xright<xleft) cimg::swap(xleft,xright,lxleft,lxright,lyleft,lyright,txleft,txright,tyleft,tyright);
philpem@5 21635 const int
philpem@5 21636 dx = xright - xleft,
philpem@5 21637 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
philpem@5 21638 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
philpem@5 21639 dtx = txright>txleft?txright - txleft:txleft - txright,
philpem@5 21640 dty = tyright>tyleft?tyright - tyleft:tyleft - tyright,
philpem@5 21641 rlx = dx?(lxright - lxleft)/dx:0,
philpem@5 21642 rly = dx?(lyright - lyleft)/dx:0,
philpem@5 21643 rtx = dx?(txright - txleft)/dx:0,
philpem@5 21644 rty = dx?(tyright - tyleft)/dx:0,
philpem@5 21645 slx = lxright>lxleft?1:-1,
philpem@5 21646 sly = lyright>lyleft?1:-1,
philpem@5 21647 stx = txright>txleft?1:-1,
philpem@5 21648 sty = tyright>tyleft?1:-1,
philpem@5 21649 ndlx = dlx - (dx?dx*(dlx/dx):0),
philpem@5 21650 ndly = dly - (dx?dx*(dly/dx):0),
philpem@5 21651 ndtx = dtx - (dx?dx*(dtx/dx):0),
philpem@5 21652 ndty = dty - (dx?dx*(dty/dx):0);
philpem@5 21653 int errlx = dx>>1, errly = errlx, errtx = errlx, errty = errlx;
philpem@5 21654 if (xleft<0 && dx) {
philpem@5 21655 lxleft-=xleft*(lxright - lxleft)/dx;
philpem@5 21656 lyleft-=xleft*(lyright - lyleft)/dx;
philpem@5 21657 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21658 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21659 }
philpem@5 21660 if (xleft<0) xleft = 0;
philpem@5 21661 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21662 T* ptrd = ptr(xleft,y,0,0);
philpem@5 21663 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 21664 const tl l = light(lxleft,lyleft);
philpem@5 21665 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 21666 cimg_forV(*this,k) {
philpem@5 21667 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21668 ptrd+=whz; col+=twhz;
philpem@5 21669 }
philpem@5 21670 ptrd-=offx;
philpem@5 21671 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21672 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21673 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 21674 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 21675 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 21676 const tl l = light(lxleft,lyleft);
philpem@5 21677 const tc *col = texture.ptr(txleft,tyleft);
philpem@5 21678 cimg_forV(*this,k) {
philpem@5 21679 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21680 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21681 ptrd+=whz; col+=twhz;
philpem@5 21682 }
philpem@5 21683 ptrd-=offx;
philpem@5 21684 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21685 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21686 txleft+=rtx+((errtx-=ndtx)<0?errtx+=dx,stx:0);
philpem@5 21687 tyleft+=rty+((errty-=ndty)<0?errty+=dx,sty:0);
philpem@5 21688 }
philpem@5 21689 }
philpem@5 21690 return *this;
philpem@5 21691 }
philpem@5 21692
philpem@5 21693 //! Draw a 2D Pseudo-Phong-shaded textured triangle, with perspective correction.
philpem@5 21694 template<typename tc, typename tl>
philpem@5 21695 CImg<T>& draw_triangle(const int x0, const int y0, const float z0,
philpem@5 21696 const int x1, const int y1, const float z1,
philpem@5 21697 const int x2, const int y2, const float z2,
philpem@5 21698 const CImg<tc>& texture,
philpem@5 21699 const int tx0, const int ty0,
philpem@5 21700 const int tx1, const int ty1,
philpem@5 21701 const int tx2, const int ty2,
philpem@5 21702 const CImg<tl>& light,
philpem@5 21703 const int lx0, const int ly0,
philpem@5 21704 const int lx1, const int ly1,
philpem@5 21705 const int lx2, const int ly2,
philpem@5 21706 const float opacity=1) {
philpem@5 21707 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 21708 if (!texture || texture.dim<dim)
philpem@5 21709 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21710 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21711 if (!light)
philpem@5 21712 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
philpem@5 21713 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
philpem@5 21714 if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21715 if (is_overlapped(light)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21716 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21717 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21718 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz-1;
philpem@5 21719 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21720 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
philpem@5 21721 float
philpem@5 21722 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 21723 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 21724 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 21725 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 21726 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
philpem@5 21727 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
philpem@5 21728 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
philpem@5 21729 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21730 float
philpem@5 21731 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 21732 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 21733 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 21734 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 21735 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 21736 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 21737 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 21738 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 21739 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 21740 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 21741 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 21742 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 21743 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 21744 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 21745 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 21746 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
philpem@5 21747 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
philpem@5 21748 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 21749 int
philpem@5 21750 xleft = xleft0, xright = xright0,
philpem@5 21751 lxleft = lxleft0, lxright = lxright0,
philpem@5 21752 lyleft = lyleft0, lyright = lyright0;
philpem@5 21753 float
philpem@5 21754 zleft = zl, zright = zr,
philpem@5 21755 txleft = txl, txright = txr,
philpem@5 21756 tyleft = tyl, tyright = tyr;
philpem@5 21757 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
philpem@5 21758 const int
philpem@5 21759 dx = xright - xleft,
philpem@5 21760 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
philpem@5 21761 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
philpem@5 21762 rlx = dx?(lxright - lxleft)/dx:0,
philpem@5 21763 rly = dx?(lyright - lyleft)/dx:0,
philpem@5 21764 slx = lxright>lxleft?1:-1,
philpem@5 21765 sly = lyright>lyleft?1:-1,
philpem@5 21766 ndlx = dlx - (dx?dx*(dlx/dx):0),
philpem@5 21767 ndly = dly - (dx?dx*(dly/dx):0);
philpem@5 21768 const float
philpem@5 21769 pentez = (zright - zleft)/dx,
philpem@5 21770 pentetx = (txright - txleft)/dx,
philpem@5 21771 pentety = (tyright - tyleft)/dx;
philpem@5 21772 int errlx = dx>>1, errly = errlx;
philpem@5 21773 if (xleft<0 && dx) {
philpem@5 21774 zleft-=xleft*(zright - zleft)/dx;
philpem@5 21775 lxleft-=xleft*(lxright - lxleft)/dx;
philpem@5 21776 lyleft-=xleft*(lyright - lyleft)/dx;
philpem@5 21777 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21778 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21779 }
philpem@5 21780 if (xleft<0) xleft = 0;
philpem@5 21781 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21782 T* ptrd = ptr(xleft,y,0,0);
philpem@5 21783 if (opacity>=1) for (int x = xleft; x<=xright; ++x) {
philpem@5 21784 const float invz = 1/zleft;
philpem@5 21785 const tl l = light(lxleft,lyleft);
philpem@5 21786 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21787 cimg_forV(*this,k) {
philpem@5 21788 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21789 ptrd+=whz; col+=twhz;
philpem@5 21790 }
philpem@5 21791 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21792 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21793 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21794 } else for (int x = xleft; x<=xright; ++x) {
philpem@5 21795 const float invz = 1/zleft;
philpem@5 21796 const tl l = light(lxleft,lyleft);
philpem@5 21797 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21798 cimg_forV(*this,k) {
philpem@5 21799 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21800 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21801 ptrd+=whz; col+=twhz;
philpem@5 21802 }
philpem@5 21803 ptrd-=offx; zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21804 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21805 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21806 }
philpem@5 21807 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 21808 }
philpem@5 21809 return *this;
philpem@5 21810 }
philpem@5 21811
philpem@5 21812 //! Draw a 2D Pseudo-Phong-shaded textured triangle, with z-buffering and perspective correction.
philpem@5 21813 template<typename tc, typename tl>
philpem@5 21814 CImg<T>& draw_triangle(float *const zbuffer,
philpem@5 21815 const int x0, const int y0, const float z0,
philpem@5 21816 const int x1, const int y1, const float z1,
philpem@5 21817 const int x2, const int y2, const float z2,
philpem@5 21818 const CImg<tc>& texture,
philpem@5 21819 const int tx0, const int ty0,
philpem@5 21820 const int tx1, const int ty1,
philpem@5 21821 const int tx2, const int ty2,
philpem@5 21822 const CImg<tl>& light,
philpem@5 21823 const int lx0, const int ly0,
philpem@5 21824 const int lx1, const int ly1,
philpem@5 21825 const int lx2, const int ly2,
philpem@5 21826 const float opacity=1) {
philpem@5 21827 if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this;
philpem@5 21828 if (!texture || texture.dim<dim)
philpem@5 21829 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is not a valid argument.",
philpem@5 21830 pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data);
philpem@5 21831 if (!light)
philpem@5 21832 throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.",
philpem@5 21833 pixel_type(),light.width,light.height,light.depth,light.dim,light.data);
philpem@5 21834 if (is_overlapped(texture)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
philpem@5 21835 +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21836 if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,
philpem@5 21837 texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity);
philpem@5 21838 static const T maxval = (T)cimg::min(cimg::type<T>::max(),cimg::type<tc>::max());
philpem@5 21839 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 21840 const int whz = width*height*depth, twhz = texture.width*texture.height*texture.depth, offx = dim*whz;
philpem@5 21841 int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2,
philpem@5 21842 nlx0 = lx0, nly0 = ly0, nlx1 = lx1, nly1 = ly1, nlx2 = lx2, nly2 = ly2;
philpem@5 21843 float
philpem@5 21844 ntx0 = tx0/z0, nty0 = ty0/z0,
philpem@5 21845 ntx1 = tx1/z1, nty1 = ty1/z1,
philpem@5 21846 ntx2 = tx2/z2, nty2 = ty2/z2,
philpem@5 21847 nz0 = 1/z0, nz1 = 1/z1, nz2 = 1/z2;
philpem@5 21848 if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1,nz0,nz1);
philpem@5 21849 if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2,nz0,nz2);
philpem@5 21850 if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2,nz1,nz2);
philpem@5 21851 if (ny0>=dimy() || ny2<0) return *this;
philpem@5 21852 float
philpem@5 21853 ptxl = (ntx1 - ntx0)/(ny1 - ny0),
philpem@5 21854 ptxr = (ntx2 - ntx0)/(ny2 - ny0),
philpem@5 21855 ptxn = (ntx2 - ntx1)/(ny2 - ny1),
philpem@5 21856 ptyl = (nty1 - nty0)/(ny1 - ny0),
philpem@5 21857 ptyr = (nty2 - nty0)/(ny2 - ny0),
philpem@5 21858 ptyn = (nty2 - nty1)/(ny2 - ny1),
philpem@5 21859 pzl = (nz1 - nz0)/(ny1 - ny0),
philpem@5 21860 pzr = (nz2 - nz0)/(ny2 - ny0),
philpem@5 21861 pzn = (nz2 - nz1)/(ny2 - ny1),
philpem@5 21862 zr = ny0>=0?nz0:(nz0 - ny0*(nz2 - nz0)/(ny2 - ny0)),
philpem@5 21863 txr = ny0>=0?ntx0:(ntx0 - ny0*(ntx2 - ntx0)/(ny2 - ny0)),
philpem@5 21864 tyr = ny0>=0?nty0:(nty0 - ny0*(nty2 - nty0)/(ny2 - ny0)),
philpem@5 21865 zl = ny1>=0?(ny0>=0?nz0:(nz0 - ny0*(nz1 - nz0)/(ny1 - ny0))):(pzl=pzn,(nz1 - ny1*(nz2 - nz1)/(ny2 - ny1))),
philpem@5 21866 txl = ny1>=0?(ny0>=0?ntx0:(ntx0 - ny0*(ntx1 - ntx0)/(ny1 - ny0))):(ptxl=ptxn,(ntx1 - ny1*(ntx2 - ntx1)/(ny2 - ny1))),
philpem@5 21867 tyl = ny1>=0?(ny0>=0?nty0:(nty0 - ny0*(nty1 - nty0)/(ny1 - ny0))):(ptyl=ptyn,(nty1 - ny1*(nty2 - nty1)/(ny2 - ny1)));
philpem@5 21868 _cimg_for_triangle3(*this,xleft0,lxleft0,lyleft0,xright0,lxright0,lyright0,y,
philpem@5 21869 nx0,ny0,nlx0,nly0,nx1,ny1,nlx1,nly1,nx2,ny2,nlx2,nly2) {
philpem@5 21870 if (y==ny1) { zl = nz1; txl = ntx1; tyl = nty1; pzl = pzn; ptxl = ptxn; ptyl = ptyn; }
philpem@5 21871 int
philpem@5 21872 xleft = xleft0, xright = xright0,
philpem@5 21873 lxleft = lxleft0, lxright = lxright0,
philpem@5 21874 lyleft = lyleft0, lyright = lyright0;
philpem@5 21875 float
philpem@5 21876 zleft = zl, zright = zr,
philpem@5 21877 txleft = txl, txright = txr,
philpem@5 21878 tyleft = tyl, tyright = tyr;
philpem@5 21879 if (xright<xleft) cimg::swap(xleft,xright,zleft,zright,txleft,txright,tyleft,tyright,lxleft,lxright,lyleft,lyright);
philpem@5 21880 const int
philpem@5 21881 dx = xright - xleft,
philpem@5 21882 dlx = lxright>lxleft?lxright - lxleft:lxleft - lxright,
philpem@5 21883 dly = lyright>lyleft?lyright - lyleft:lyleft - lyright,
philpem@5 21884 rlx = dx?(lxright - lxleft)/dx:0,
philpem@5 21885 rly = dx?(lyright - lyleft)/dx:0,
philpem@5 21886 slx = lxright>lxleft?1:-1,
philpem@5 21887 sly = lyright>lyleft?1:-1,
philpem@5 21888 ndlx = dlx - (dx?dx*(dlx/dx):0),
philpem@5 21889 ndly = dly - (dx?dx*(dly/dx):0);
philpem@5 21890 const float
philpem@5 21891 pentez = (zright - zleft)/dx,
philpem@5 21892 pentetx = (txright - txleft)/dx,
philpem@5 21893 pentety = (tyright - tyleft)/dx;
philpem@5 21894 int errlx = dx>>1, errly = errlx;
philpem@5 21895 if (xleft<0 && dx) {
philpem@5 21896 zleft-=xleft*(zright - zleft)/dx;
philpem@5 21897 lxleft-=xleft*(lxright - lxleft)/dx;
philpem@5 21898 lyleft-=xleft*(lyright - lyleft)/dx;
philpem@5 21899 txleft-=xleft*(txright - txleft)/dx;
philpem@5 21900 tyleft-=xleft*(tyright - tyleft)/dx;
philpem@5 21901 }
philpem@5 21902 if (xleft<0) xleft = 0;
philpem@5 21903 if (xright>=dimx()-1) xright = dimx()-1;
philpem@5 21904 T* ptrd = ptr(xleft,y);
philpem@5 21905 float *ptrz = zbuffer + xleft + y*width;
philpem@5 21906 if (opacity>=1) for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 21907 if (zleft>*ptrz) {
philpem@5 21908 *ptrz = zleft;
philpem@5 21909 const float invz = 1/zleft;
philpem@5 21910 const tl l = light(lxleft,lyleft);
philpem@5 21911 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21912 cimg_forV(*this,k) {
philpem@5 21913 *ptrd = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21914 ptrd+=whz; col+=twhz;
philpem@5 21915 }
philpem@5 21916 ptrd-=offx;
philpem@5 21917 }
philpem@5 21918 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21919 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21920 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21921 } else for (int x = xleft; x<=xright; ++x, ++ptrz, ++ptrd) {
philpem@5 21922 if (zleft>*ptrz) {
philpem@5 21923 *ptrz = zleft;
philpem@5 21924 const float invz = 1/zleft;
philpem@5 21925 const tl l = light(lxleft,lyleft);
philpem@5 21926 const tc *col = texture.ptr((int)(txleft*invz),(int)(tyleft*invz));
philpem@5 21927 cimg_forV(*this,k) {
philpem@5 21928 const T val = (T)(l<1?l**col:(2-l)**col+(l-1)*maxval);
philpem@5 21929 *ptrd = (T)(nopacity*val + *ptrd*copacity);
philpem@5 21930 ptrd+=whz; col+=twhz;
philpem@5 21931 }
philpem@5 21932 ptrd-=offx;
philpem@5 21933 }
philpem@5 21934 zleft+=pentez; txleft+=pentetx; tyleft+=pentety;
philpem@5 21935 lxleft+=rlx+((errlx-=ndlx)<0?errlx+=dx,slx:0);
philpem@5 21936 lyleft+=rly+((errly-=ndly)<0?errly+=dx,sly:0);
philpem@5 21937 }
philpem@5 21938 zr+=pzr; txr+=ptxr; tyr+=ptyr; zl+=pzl; txl+=ptxl; tyl+=ptyl;
philpem@5 21939 }
philpem@5 21940 return *this;
philpem@5 21941 }
philpem@5 21942
philpem@5 21943 // Draw a 2D ellipse (inner routine).
philpem@5 21944 template<typename tc>
philpem@5 21945 CImg<T>& _draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
philpem@5 21946 const tc *const color, const float opacity,
philpem@5 21947 const unsigned int pattern) {
philpem@5 21948 if (is_empty()) return *this;
philpem@5 21949 if (!color)
philpem@5 21950 throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",
philpem@5 21951 pixel_type());
philpem@5 21952 _draw_scanline(color,opacity);
philpem@5 21953 const float
philpem@5 21954 nr1 = cimg::abs(r1), nr2 = cimg::abs(r2),
philpem@5 21955 norm = (float)cimg_std::sqrt(ru*ru+rv*rv),
philpem@5 21956 u = norm>0?ru/norm:1,
philpem@5 21957 v = norm>0?rv/norm:0,
philpem@5 21958 rmax = cimg::max(nr1,nr2),
philpem@5 21959 l1 = (float)cimg_std::pow(rmax/(nr1>0?nr1:1e-6),2),
philpem@5 21960 l2 = (float)cimg_std::pow(rmax/(nr2>0?nr2:1e-6),2),
philpem@5 21961 a = l1*u*u + l2*v*v,
philpem@5 21962 b = u*v*(l1-l2),
philpem@5 21963 c = l1*v*v + l2*u*u;
philpem@5 21964 const int
philpem@5 21965 yb = (int)cimg_std::sqrt(a*rmax*rmax/(a*c-b*b)),
philpem@5 21966 tymin = y0 - yb - 1,
philpem@5 21967 tymax = y0 + yb + 1,
philpem@5 21968 ymin = tymin<0?0:tymin,
philpem@5 21969 ymax = tymax>=dimy()?height-1:tymax;
philpem@5 21970 int oxmin = 0, oxmax = 0;
philpem@5 21971 bool first_line = true;
philpem@5 21972 for (int y = ymin; y<=ymax; ++y) {
philpem@5 21973 const float
philpem@5 21974 Y = y-y0 + (y<y0?0.5f:-0.5f),
philpem@5 21975 delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax),
philpem@5 21976 sdelta = delta>0?(float)cimg_std::sqrt(delta)/a:0.0f,
philpem@5 21977 bY = b*Y/a,
philpem@5 21978 fxmin = x0-0.5f-bY-sdelta,
philpem@5 21979 fxmax = x0+0.5f-bY+sdelta;
philpem@5 21980 const int xmin = (int)fxmin, xmax = (int)fxmax;
philpem@5 21981 if (!pattern) _draw_scanline(xmin,xmax,y,color,opacity);
philpem@5 21982 else {
philpem@5 21983 if (first_line) {
philpem@5 21984 if (y0-yb>=0) _draw_scanline(xmin,xmax,y,color,opacity);
philpem@5 21985 else draw_point(xmin,y,color,opacity).draw_point(xmax,y,color,opacity);
philpem@5 21986 first_line = false;
philpem@5 21987 } else {
philpem@5 21988 if (xmin<oxmin) _draw_scanline(xmin,oxmin-1,y,color,opacity);
philpem@5 21989 else _draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity);
philpem@5 21990 if (xmax<oxmax) _draw_scanline(xmax,oxmax-1,y,color,opacity);
philpem@5 21991 else _draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity);
philpem@5 21992 if (y==tymax) _draw_scanline(xmin+1,xmax-1,y,color,opacity);
philpem@5 21993 }
philpem@5 21994 }
philpem@5 21995 oxmin = xmin; oxmax = xmax;
philpem@5 21996 }
philpem@5 21997 return *this;
philpem@5 21998 }
philpem@5 21999
philpem@5 22000 //! Draw a filled ellipse.
philpem@5 22001 /**
philpem@5 22002 \param x0 = X-coordinate of the ellipse center.
philpem@5 22003 \param y0 = Y-coordinate of the ellipse center.
philpem@5 22004 \param r1 = First radius of the ellipse.
philpem@5 22005 \param r2 = Second radius of the ellipse.
philpem@5 22006 \param ru = X-coordinate of the orientation vector related to the first radius.
philpem@5 22007 \param rv = Y-coordinate of the orientation vector related to the first radius.
philpem@5 22008 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 22009 \param opacity = opacity of the drawing.
philpem@5 22010 **/
philpem@5 22011 template<typename tc>
philpem@5 22012 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
philpem@5 22013 const tc *const color, const float opacity=1) {
philpem@5 22014 return _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,0U);
philpem@5 22015 }
philpem@5 22016
philpem@5 22017 //! Draw a filled ellipse.
philpem@5 22018 template<typename tc>
philpem@5 22019 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
philpem@5 22020 const CImg<tc>& color, const float opacity=1) {
philpem@5 22021 return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity);
philpem@5 22022 }
philpem@5 22023
philpem@5 22024 //! Draw a filled ellipse.
philpem@5 22025 /**
philpem@5 22026 \param x0 = X-coordinate of the ellipse center.
philpem@5 22027 \param y0 = Y-coordinate of the ellipse center.
philpem@5 22028 \param tensor = Diffusion tensor describing the ellipse.
philpem@5 22029 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 22030 \param opacity = opacity of the drawing.
philpem@5 22031 **/
philpem@5 22032 template<typename t, typename tc>
philpem@5 22033 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
philpem@5 22034 const tc *const color, const float opacity=1) {
philpem@5 22035 CImgList<t> eig = tensor.get_symmetric_eigen();
philpem@5 22036 const CImg<t> &val = eig[0], &vec = eig[1];
philpem@5 22037 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity);
philpem@5 22038 }
philpem@5 22039
philpem@5 22040 //! Draw a filled ellipse.
philpem@5 22041 template<typename t, typename tc>
philpem@5 22042 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
philpem@5 22043 const CImg<tc>& color, const float opacity=1) {
philpem@5 22044 return draw_ellipse(x0,y0,tensor,color.data,opacity);
philpem@5 22045 }
philpem@5 22046
philpem@5 22047 //! Draw an outlined ellipse.
philpem@5 22048 /**
philpem@5 22049 \param x0 = X-coordinate of the ellipse center.
philpem@5 22050 \param y0 = Y-coordinate of the ellipse center.
philpem@5 22051 \param r1 = First radius of the ellipse.
philpem@5 22052 \param r2 = Second radius of the ellipse.
philpem@5 22053 \param ru = X-coordinate of the orientation vector related to the first radius.
philpem@5 22054 \param rv = Y-coordinate of the orientation vector related to the first radius.
philpem@5 22055 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 22056 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
philpem@5 22057 \param opacity = opacity of the drawing.
philpem@5 22058 **/
philpem@5 22059 template<typename tc>
philpem@5 22060 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
philpem@5 22061 const tc *const color, const float opacity,
philpem@5 22062 const unsigned int pattern) {
philpem@5 22063 if (pattern) _draw_ellipse(x0,y0,r1,r2,ru,rv,color,opacity,pattern);
philpem@5 22064 return *this;
philpem@5 22065 }
philpem@5 22066
philpem@5 22067 //! Draw an outlined ellipse.
philpem@5 22068 template<typename tc>
philpem@5 22069 CImg<T>& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float ru, const float rv,
philpem@5 22070 const CImg<tc>& color, const float opacity,
philpem@5 22071 const unsigned int pattern) {
philpem@5 22072 return draw_ellipse(x0,y0,r1,r2,ru,rv,color.data,opacity,pattern);
philpem@5 22073 }
philpem@5 22074
philpem@5 22075 //! Draw an outlined ellipse.
philpem@5 22076 /**
philpem@5 22077 \param x0 = X-coordinate of the ellipse center.
philpem@5 22078 \param y0 = Y-coordinate of the ellipse center.
philpem@5 22079 \param tensor = Diffusion tensor describing the ellipse.
philpem@5 22080 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 22081 \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern.
philpem@5 22082 \param opacity = opacity of the drawing.
philpem@5 22083 **/
philpem@5 22084 template<typename t, typename tc>
philpem@5 22085 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
philpem@5 22086 const tc *const color, const float opacity,
philpem@5 22087 const unsigned int pattern) {
philpem@5 22088 CImgList<t> eig = tensor.get_symmetric_eigen();
philpem@5 22089 const CImg<t> &val = eig[0], &vec = eig[1];
philpem@5 22090 return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,opacity,pattern);
philpem@5 22091 }
philpem@5 22092
philpem@5 22093 //! Draw an outlined ellipse.
philpem@5 22094 template<typename t, typename tc>
philpem@5 22095 CImg<T>& draw_ellipse(const int x0, const int y0, const CImg<t> &tensor,
philpem@5 22096 const CImg<tc>& color, const float opacity,
philpem@5 22097 const unsigned int pattern) {
philpem@5 22098 return draw_ellipse(x0,y0,tensor,color.data,opacity,pattern);
philpem@5 22099 }
philpem@5 22100
philpem@5 22101 //! Draw a filled circle.
philpem@5 22102 /**
philpem@5 22103 \param x0 X-coordinate of the circle center.
philpem@5 22104 \param y0 Y-coordinate of the circle center.
philpem@5 22105 \param radius Circle radius.
philpem@5 22106 \param color Array of dimv() values of type \c T, defining the drawing color.
philpem@5 22107 \param opacity Drawing opacity.
philpem@5 22108 \note
philpem@5 22109 - Circle version of the Bresenham's algorithm is used.
philpem@5 22110 **/
philpem@5 22111 template<typename tc>
philpem@5 22112 CImg<T>& draw_circle(const int x0, const int y0, int radius,
philpem@5 22113 const tc *const color, const float opacity=1) {
philpem@5 22114 if (!is_empty()) {
philpem@5 22115 if (!color)
philpem@5 22116 throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
philpem@5 22117 pixel_type());
philpem@5 22118 _draw_scanline(color,opacity);
philpem@5 22119 if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
philpem@5 22120 if (y0>=0 && y0<dimy()) _draw_scanline(x0-radius,x0+radius,y0,color,opacity);
philpem@5 22121 for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
philpem@5 22122 if (f>=0) {
philpem@5 22123 const int x1 = x0-x, x2 = x0+x, y1 = y0-y, y2 = y0+y;
philpem@5 22124 if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
philpem@5 22125 if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
philpem@5 22126 f+=(ddFy+=2); --y;
philpem@5 22127 }
philpem@5 22128 const bool no_diag = y!=(x++);
philpem@5 22129 ++(f+=(ddFx+=2));
philpem@5 22130 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x;
philpem@5 22131 if (no_diag) {
philpem@5 22132 if (y1>=0 && y1<dimy()) _draw_scanline(x1,x2,y1,color,opacity);
philpem@5 22133 if (y2>=0 && y2<dimy()) _draw_scanline(x1,x2,y2,color,opacity);
philpem@5 22134 }
philpem@5 22135 }
philpem@5 22136 }
philpem@5 22137 return *this;
philpem@5 22138 }
philpem@5 22139
philpem@5 22140 //! Draw a filled circle.
philpem@5 22141 template<typename tc>
philpem@5 22142 CImg<T>& draw_circle(const int x0, const int y0, int radius,
philpem@5 22143 const CImg<tc>& color, const float opacity=1) {
philpem@5 22144 return draw_circle(x0,y0,radius,color.data,opacity);
philpem@5 22145 }
philpem@5 22146
philpem@5 22147 //! Draw an outlined circle.
philpem@5 22148 /**
philpem@5 22149 \param x0 X-coordinate of the circle center.
philpem@5 22150 \param y0 Y-coordinate of the circle center.
philpem@5 22151 \param radius Circle radius.
philpem@5 22152 \param color Array of dimv() values of type \c T, defining the drawing color.
philpem@5 22153 \param opacity Drawing opacity.
philpem@5 22154 **/
philpem@5 22155 template<typename tc>
philpem@5 22156 CImg<T>& draw_circle(const int x0, const int y0, int radius,
philpem@5 22157 const tc *const color, const float opacity,
philpem@5 22158 const unsigned int) {
philpem@5 22159 if (!is_empty()) {
philpem@5 22160 if (!color)
philpem@5 22161 throw CImgArgumentException("CImg<%s>::draw_circle : Specified color is (null).",
philpem@5 22162 pixel_type());
philpem@5 22163 if (radius<0 || x0-radius>=dimx() || y0+radius<0 || y0-radius>=dimy()) return *this;
philpem@5 22164 if (!radius) return draw_point(x0,y0,color,opacity);
philpem@5 22165 draw_point(x0-radius,y0,color,opacity).draw_point(x0+radius,y0,color,opacity).
philpem@5 22166 draw_point(x0,y0-radius,color,opacity).draw_point(x0,y0+radius,color,opacity);
philpem@5 22167 if (radius==1) return *this;
philpem@5 22168 for (int f=1-radius, ddFx=0, ddFy=-(radius<<1), x=0, y=radius; x<y; ) {
philpem@5 22169 if (f>=0) { f+=(ddFy+=2); --y; }
philpem@5 22170 ++x; ++(f+=(ddFx+=2));
philpem@5 22171 if (x!=y+1) {
philpem@5 22172 const int x1 = x0-y, x2 = x0+y, y1 = y0-x, y2 = y0+x, x3 = x0-x, x4 = x0+x, y3 = y0-y, y4 = y0+y;
philpem@5 22173 draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity).
philpem@5 22174 draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity);
philpem@5 22175 if (x!=y)
philpem@5 22176 draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity).
philpem@5 22177 draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity);
philpem@5 22178 }
philpem@5 22179 }
philpem@5 22180 }
philpem@5 22181 return *this;
philpem@5 22182 }
philpem@5 22183
philpem@5 22184 //! Draw an outlined circle.
philpem@5 22185 template<typename tc>
philpem@5 22186 CImg<T>& draw_circle(const int x0, const int y0, int radius, const CImg<tc>& color,
philpem@5 22187 const float opacity,
philpem@5 22188 const unsigned int pattern) {
philpem@5 22189 return draw_circle(x0,y0,radius,color.data,opacity,pattern);
philpem@5 22190 }
philpem@5 22191
philpem@5 22192 // Draw a text (internal).
philpem@5 22193 template<typename tc1, typename tc2, typename t>
philpem@5 22194 CImg<T>& _draw_text(const int x0, const int y0, const char *const text,
philpem@5 22195 const tc1 *const foreground_color, const tc2 *const background_color,
philpem@5 22196 const float opacity, const CImgList<t>& font) {
philpem@5 22197 if (!text) return *this;
philpem@5 22198 if (!font)
philpem@5 22199 throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.",
philpem@5 22200 pixel_type(),font.size,font.data);
philpem@5 22201 const int text_length = cimg::strlen(text);
philpem@5 22202
philpem@5 22203 if (is_empty()) {
philpem@5 22204 // If needed, pre-compute necessary size of the image
philpem@5 22205 int x = 0, y = 0, w = 0;
philpem@5 22206 unsigned char c = 0;
philpem@5 22207 for (int i = 0; i<text_length; ++i) {
philpem@5 22208 c = text[i];
philpem@5 22209 switch (c) {
philpem@5 22210 case '\n' : y+=font[' '].height; if (x>w) w = x; x = 0; break;
philpem@5 22211 case '\t' : x+=4*font[' '].width; break;
philpem@5 22212 default : if (c<font.size) x+=font[c].width;
philpem@5 22213 }
philpem@5 22214 }
philpem@5 22215 if (x!=0 || c=='\n') {
philpem@5 22216 if (x>w) w=x;
philpem@5 22217 y+=font[' '].height;
philpem@5 22218 }
philpem@5 22219 assign(x0+w,y0+y,1,font[' '].dim,0);
philpem@5 22220 if (background_color) cimg_forV(*this,k) get_shared_channel(k).fill((T)background_color[k]);
philpem@5 22221 }
philpem@5 22222
philpem@5 22223 int x = x0, y = y0;
philpem@5 22224 CImg<T> letter;
philpem@5 22225 for (int i = 0; i<text_length; ++i) {
philpem@5 22226 const unsigned char c = text[i];
philpem@5 22227 switch (c) {
philpem@5 22228 case '\n' : y+=font[' '].height; x = x0; break;
philpem@5 22229 case '\t' : x+=4*font[' '].width; break;
philpem@5 22230 default : if (c<font.size) {
philpem@5 22231 letter = font[c];
philpem@5 22232 const CImg<T>& mask = (c+256)<(int)font.size?font[c+256]:font[c];
philpem@5 22233 if (foreground_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
philpem@5 22234 if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*foreground_color[k]);
philpem@5 22235 if (background_color) for (unsigned int p = 0; p<letter.width*letter.height; ++p)
philpem@5 22236 if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)background_color[k];
philpem@5 22237 if (!background_color && font.size>=512) draw_image(x,y,letter,mask,opacity,(T)1);
philpem@5 22238 else draw_image(x,y,letter,opacity);
philpem@5 22239 x+=letter.width;
philpem@5 22240 }
philpem@5 22241 }
philpem@5 22242 }
philpem@5 22243 return *this;
philpem@5 22244 }
philpem@5 22245
philpem@5 22246 //! Draw a text.
philpem@5 22247 /**
philpem@5 22248 \param x0 X-coordinate of the text in the instance image.
philpem@5 22249 \param y0 Y-coordinate of the text in the instance image.
philpem@5 22250 \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
philpem@5 22251 \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
philpem@5 22252 \param font Font used for drawing text.
philpem@5 22253 \param opacity Drawing opacity.
philpem@5 22254 \param format 'printf'-style format string, followed by arguments.
philpem@5 22255 \note Clipping is supported.
philpem@5 22256 **/
philpem@5 22257 template<typename tc1, typename tc2, typename t>
philpem@5 22258 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22259 const tc1 *const foreground_color, const tc2 *const background_color,
philpem@5 22260 const float opacity, const CImgList<t>& font, ...) {
philpem@5 22261 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
philpem@5 22262 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22263 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
philpem@5 22264 }
philpem@5 22265
philpem@5 22266 //! Draw a text.
philpem@5 22267 template<typename tc1, typename tc2, typename t>
philpem@5 22268 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22269 const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
philpem@5 22270 const float opacity, const CImgList<t>& font, ...) {
philpem@5 22271 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
philpem@5 22272 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22273 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
philpem@5 22274 }
philpem@5 22275
philpem@5 22276 //! Draw a text.
philpem@5 22277 template<typename tc, typename t>
philpem@5 22278 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22279 const tc *const foreground_color, const int background_color,
philpem@5 22280 const float opacity, const CImgList<t>& font, ...) {
philpem@5 22281 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
philpem@5 22282 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22283 return _draw_text(x0,y0,tmp,foreground_color,(tc*)background_color,opacity,font);
philpem@5 22284 }
philpem@5 22285
philpem@5 22286 //! Draw a text.
philpem@5 22287 template<typename tc, typename t>
philpem@5 22288 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22289 const int foreground_color, const tc *const background_color,
philpem@5 22290 const float opacity, const CImgList<t>& font, ...) {
philpem@5 22291 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font);
philpem@5 22292 cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22293 return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
philpem@5 22294 }
philpem@5 22295
philpem@5 22296 //! Draw a text.
philpem@5 22297 /**
philpem@5 22298 \param x0 X-coordinate of the text in the instance image.
philpem@5 22299 \param y0 Y-coordinate of the text in the instance image.
philpem@5 22300 \param foreground_color Array of dimv() values of type \c T, defining the foreground color (0 means 'transparent').
philpem@5 22301 \param background_color Array of dimv() values of type \c T, defining the background color (0 means 'transparent').
philpem@5 22302 \param font_size Size of the font (nearest match).
philpem@5 22303 \param opacity Drawing opacity.
philpem@5 22304 \param format 'printf'-style format string, followed by arguments.
philpem@5 22305 \note Clipping is supported.
philpem@5 22306 **/
philpem@5 22307 template<typename tc1, typename tc2>
philpem@5 22308 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22309 const tc1 *const foreground_color, const tc2 *const background_color,
philpem@5 22310 const float opacity=1, const unsigned int font_size=11, ...) {
philpem@5 22311 static CImgList<T> font;
philpem@5 22312 static unsigned int fsize = 0;
philpem@5 22313 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
philpem@5 22314 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22315 return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font);
philpem@5 22316 }
philpem@5 22317
philpem@5 22318 //! Draw a text.
philpem@5 22319 template<typename tc1, typename tc2>
philpem@5 22320 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22321 const CImg<tc1>& foreground_color, const CImg<tc2>& background_color,
philpem@5 22322 const float opacity=1, const unsigned int font_size=11, ...) {
philpem@5 22323 static CImgList<T> font;
philpem@5 22324 static unsigned int fsize = 0;
philpem@5 22325 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
philpem@5 22326 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22327 return _draw_text(x0,y0,tmp,foreground_color.data,background_color.data,opacity,font);
philpem@5 22328 }
philpem@5 22329
philpem@5 22330 //! Draw a text.
philpem@5 22331 template<typename tc>
philpem@5 22332 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22333 const tc *const foreground_color, const int background_color=0,
philpem@5 22334 const float opacity=1, const unsigned int font_size=11, ...) {
philpem@5 22335 static CImgList<T> font;
philpem@5 22336 static unsigned int fsize = 0;
philpem@5 22337 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
philpem@5 22338 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22339 return _draw_text(x0,y0,tmp,foreground_color,(const tc*)background_color,opacity,font);
philpem@5 22340 }
philpem@5 22341
philpem@5 22342 //! Draw a text.
philpem@5 22343 template<typename tc>
philpem@5 22344 CImg<T>& draw_text(const int x0, const int y0, const char *const text,
philpem@5 22345 const int foreground_color, const tc *const background_color,
philpem@5 22346 const float opacity=1, const unsigned int font_size=11, ...) {
philpem@5 22347 static CImgList<T> font;
philpem@5 22348 static unsigned int fsize = 0;
philpem@5 22349 if (fsize!=font_size) { font = CImgList<T>::font(font_size); fsize = font_size; }
philpem@5 22350 char tmp[2048] = { 0 }; cimg_std::va_list ap; va_start(ap,font_size); cimg_std::vsprintf(tmp,text,ap); va_end(ap);
philpem@5 22351 return _draw_text(x0,y0,tmp,(tc*)foreground_color,background_color,opacity,font);
philpem@5 22352 }
philpem@5 22353
philpem@5 22354 //! Draw a vector field in the instance image, using a colormap.
philpem@5 22355 /**
philpem@5 22356 \param flow Image of 2d vectors used as input data.
philpem@5 22357 \param color Image of dimv()-D vectors corresponding to the color of each arrow.
philpem@5 22358 \param sampling Length (in pixels) between each arrow.
philpem@5 22359 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
philpem@5 22360 \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
philpem@5 22361 \param opacity Opacity of the drawing.
philpem@5 22362 \param pattern Used pattern to draw lines.
philpem@5 22363 \note Clipping is supported.
philpem@5 22364 **/
philpem@5 22365 template<typename t1, typename t2>
philpem@5 22366 CImg<T>& draw_quiver(const CImg<t1>& flow,
philpem@5 22367 const t2 *const color, const float opacity=1,
philpem@5 22368 const unsigned int sampling=25, const float factor=-20,
philpem@5 22369 const int quiver_type=0, const unsigned int pattern=~0U) {
philpem@5 22370 return draw_quiver(flow,CImg<t2>(color,dim,1,1,1,true),opacity,sampling,factor,quiver_type,pattern);
philpem@5 22371 }
philpem@5 22372
philpem@5 22373 //! Draw a vector field in the instance image, using a colormap.
philpem@5 22374 /**
philpem@5 22375 \param flow Image of 2d vectors used as input data.
philpem@5 22376 \param color Image of dimv()-D vectors corresponding to the color of each arrow.
philpem@5 22377 \param sampling Length (in pixels) between each arrow.
philpem@5 22378 \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length).
philpem@5 22379 \param quiver_type Type of plot. Can be 0 (arrows) or 1 (segments).
philpem@5 22380 \param opacity Opacity of the drawing.
philpem@5 22381 \param pattern Used pattern to draw lines.
philpem@5 22382 \note Clipping is supported.
philpem@5 22383 **/
philpem@5 22384 template<typename t1, typename t2>
philpem@5 22385 CImg<T>& draw_quiver(const CImg<t1>& flow,
philpem@5 22386 const CImg<t2>& color, const float opacity=1,
philpem@5 22387 const unsigned int sampling=25, const float factor=-20,
philpem@5 22388 const int quiver_type=0, const unsigned int pattern=~0U) {
philpem@5 22389 if (!is_empty()) {
philpem@5 22390 if (!flow || flow.dim!=2)
philpem@5 22391 throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.",
philpem@5 22392 pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data);
philpem@5 22393 if (sampling<=0)
philpem@5 22394 throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",
philpem@5 22395 pixel_type(),sampling);
philpem@5 22396 const bool colorfield = (color.width==flow.width && color.height==flow.height && color.depth==1 && color.dim==dim);
philpem@5 22397 if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,quiver_type,pattern);
philpem@5 22398
philpem@5 22399 float vmax,fact;
philpem@5 22400 if (factor<=0) {
philpem@5 22401 float m, M = (float)flow.get_pointwise_norm(2).maxmin(m);
philpem@5 22402 vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
philpem@5 22403 fact = -factor;
philpem@5 22404 } else { fact = factor; vmax = 1; }
philpem@5 22405
philpem@5 22406 for (unsigned int y=sampling/2; y<height; y+=sampling)
philpem@5 22407 for (unsigned int x=sampling/2; x<width; x+=sampling) {
philpem@5 22408 const unsigned int X = x*flow.width/width, Y = y*flow.height/height;
philpem@5 22409 float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax;
philpem@5 22410 if (!quiver_type) {
philpem@5 22411 const int xx = x+(int)u, yy = y+(int)v;
philpem@5 22412 if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,opacity,45,sampling/5.0f,pattern);
philpem@5 22413 else draw_arrow(x,y,xx,yy,color,opacity,45,sampling/5.0f,pattern);
philpem@5 22414 } else {
philpem@5 22415 if (colorfield) draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color.get_vector_at(X,Y),opacity,pattern);
philpem@5 22416 else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color,opacity,pattern);
philpem@5 22417 }
philpem@5 22418 }
philpem@5 22419 }
philpem@5 22420 return *this;
philpem@5 22421 }
philpem@5 22422
philpem@5 22423 //! Draw a 1D graph on the instance image.
philpem@5 22424 /**
philpem@5 22425 \param data Image containing the graph values I = f(x).
philpem@5 22426 \param color Array of dimv() values of type \c T, defining the drawing color.
philpem@5 22427 \param gtype Define the type of the plot :
philpem@5 22428 - 0 = Plot using points clouds.
philpem@5 22429 - 1 = Plot using linear interpolation (segments).
philpem@5 22430 - 2 = Plot with bars.
philpem@5 22431 - 3 = Plot using cubic interpolation (3-polynomials).
philpem@5 22432 - 4 = Plot using cross clouds.
philpem@5 22433 \param ymin Lower bound of the y-range.
philpem@5 22434 \param ymax Upper bound of the y-range.
philpem@5 22435 \param opacity Drawing opacity.
philpem@5 22436 \param pattern Drawing pattern.
philpem@5 22437 \note
philpem@5 22438 - if \c ymin==ymax==0, the y-range is computed automatically from the input sample.
philpem@5 22439 **/
philpem@5 22440 template<typename t, typename tc>
philpem@5 22441 CImg<T>& draw_graph(const CImg<t>& data,
philpem@5 22442 const tc *const color, const float opacity=1,
philpem@5 22443 const unsigned int plot_type=1, const unsigned int vertex_type=1,
philpem@5 22444 const double ymin=0, const double ymax=0,
philpem@5 22445 const unsigned int pattern=~0U) {
philpem@5 22446 if (is_empty() || height<=1) return *this;;
philpem@5 22447 const unsigned long siz = data.size();
philpem@5 22448 if (!color)
philpem@5 22449 throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",
philpem@5 22450 pixel_type());
philpem@5 22451 tc *color1 = 0, *color2 = 0;
philpem@5 22452 if (plot_type==3) {
philpem@5 22453 color1 = new tc[dim]; color2 = new tc[dim];
philpem@5 22454 cimg_forV(*this,k) { color1[k] = (tc)(color[k]*0.6f); color2[k] = (tc)(color[k]*0.3f); }
philpem@5 22455 }
philpem@5 22456
philpem@5 22457 double m = ymin, M = ymax;
philpem@5 22458 if (ymin==ymax) m = (double)data.maxmin(M);
philpem@5 22459 if (m==M) { --m; ++M; }
philpem@5 22460 const float ca = (float)(M-m)/(height-1);
philpem@5 22461 bool init_hatch = true;
philpem@5 22462
philpem@5 22463 // Draw graph edges
philpem@5 22464 switch (plot_type%4) {
philpem@5 22465 case 1 : { // Segments
philpem@5 22466 int oX = 0, oY = (int)((data[0]-m)/ca);
philpem@5 22467 for (unsigned long off = 1; off<siz; ++off) {
philpem@5 22468 const int
philpem@5 22469 X = (int)(off*width/siz),
philpem@5 22470 Y = (int)((data[off]-m)/ca);
philpem@5 22471 draw_line(oX,oY,X,Y,color,opacity,pattern,init_hatch);
philpem@5 22472 oX = X; oY = Y;
philpem@5 22473 init_hatch = false;
philpem@5 22474 }
philpem@5 22475 } break;
philpem@5 22476 case 2 : { // Spline
philpem@5 22477 const CImg<t> ndata = data.get_shared_points(0,siz-1);
philpem@5 22478 int oY = (int)((data[0]-m)/ca);
philpem@5 22479 cimg_forX(*this,x) {
philpem@5 22480 const int Y = (int)((ndata._cubic_atX((float)x*ndata.width/width)-m)/ca);
philpem@5 22481 if (x>0) draw_line(x,oY,x+1,Y,color,opacity,pattern,init_hatch);
philpem@5 22482 init_hatch = false;
philpem@5 22483 oY = Y;
philpem@5 22484 }
philpem@5 22485 } break;
philpem@5 22486 case 3 : { // Bars
philpem@5 22487 const int Y0 = (int)(-m/ca);
philpem@5 22488 int oX = 0;
philpem@5 22489 cimg_foroff(data,off) {
philpem@5 22490 const int
philpem@5 22491 X = (off+1)*width/siz-1,
philpem@5 22492 Y = (int)((data[off]-m)/ca);
philpem@5 22493 draw_rectangle(oX,Y0,X,Y,color1,opacity).
philpem@5 22494 draw_line(oX,Y,oX,Y0,color2,opacity).
philpem@5 22495 draw_line(oX,Y0,X,Y0,Y<=Y0?color2:color,opacity).
philpem@5 22496 draw_line(X,Y,X,Y0,color,opacity).
philpem@5 22497 draw_line(oX,Y,X,Y,Y<=Y0?color:color2,opacity);
philpem@5 22498 oX = X+1;
philpem@5 22499 }
philpem@5 22500 } break;
philpem@5 22501 default : break; // No edges
philpem@5 22502 }
philpem@5 22503
philpem@5 22504 // Draw graph points
philpem@5 22505 switch (vertex_type%8) {
philpem@5 22506 case 1 : { // Point
philpem@5 22507 cimg_foroff(data,off) {
philpem@5 22508 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22509 draw_point(X,Y,color,opacity);
philpem@5 22510 }
philpem@5 22511 } break;
philpem@5 22512 case 2 : { // Standard Cross
philpem@5 22513 cimg_foroff(data,off) {
philpem@5 22514 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22515 draw_line(X-3,Y,X+3,Y,color,opacity).draw_line(X,Y-3,X,Y+3,color,opacity);
philpem@5 22516 }
philpem@5 22517 } break;
philpem@5 22518 case 3 : { // Rotated Cross
philpem@5 22519 cimg_foroff(data,off) {
philpem@5 22520 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22521 draw_line(X-3,Y-3,X+3,Y+3,color,opacity).draw_line(X-3,Y+3,X+3,Y-3,color,opacity);
philpem@5 22522 }
philpem@5 22523 } break;
philpem@5 22524 case 4 : { // Filled Circle
philpem@5 22525 cimg_foroff(data,off) {
philpem@5 22526 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22527 draw_circle(X,Y,3,color,opacity);
philpem@5 22528 }
philpem@5 22529 } break;
philpem@5 22530 case 5 : { // Outlined circle
philpem@5 22531 cimg_foroff(data,off) {
philpem@5 22532 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22533 draw_circle(X,Y,3,color,opacity,0U);
philpem@5 22534 }
philpem@5 22535 } break;
philpem@5 22536 case 6 : { // Square
philpem@5 22537 cimg_foroff(data,off) {
philpem@5 22538 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22539 draw_rectangle(X-3,Y-3,X+3,Y+3,color,opacity,~0U);
philpem@5 22540 }
philpem@5 22541 } break;
philpem@5 22542 case 7 : { // Diamond
philpem@5 22543 cimg_foroff(data,off) {
philpem@5 22544 const int X = off*width/siz, Y = (int)((data[off]-m)/ca);
philpem@5 22545 draw_line(X,Y-4,X+4,Y,color,opacity).
philpem@5 22546 draw_line(X+4,Y,X,Y+4,color,opacity).
philpem@5 22547 draw_line(X,Y+4,X-4,Y,color,opacity).
philpem@5 22548 draw_line(X-4,Y,X,Y-4,color,opacity);
philpem@5 22549 }
philpem@5 22550 } break;
philpem@5 22551 default : break; // No vertices
philpem@5 22552 }
philpem@5 22553
philpem@5 22554 if (color1) delete[] color1; if (color2) delete[] color2;
philpem@5 22555 return *this;
philpem@5 22556 }
philpem@5 22557
philpem@5 22558 //! Draw a 1D graph on the instance image.
philpem@5 22559 template<typename t, typename tc>
philpem@5 22560 CImg<T>& draw_graph(const CImg<t>& data,
philpem@5 22561 const CImg<tc>& color, const float opacity=1,
philpem@5 22562 const unsigned int plot_type=1, const unsigned int vertex_type=1,
philpem@5 22563 const double ymin=0, const double ymax=0,
philpem@5 22564 const unsigned int pattern=~0U) {
philpem@5 22565 return draw_graph(data,color.data,opacity,plot_type,vertex_type,ymin,ymax,pattern);
philpem@5 22566 }
philpem@5 22567
philpem@5 22568 //! Draw a labeled horizontal axis on the instance image.
philpem@5 22569 /**
philpem@5 22570 \param xvalues Lower bound of the x-range.
philpem@5 22571 \param y Y-coordinate of the horizontal axis in the instance image.
philpem@5 22572 \param color Array of dimv() values of type \c T, defining the drawing color.
philpem@5 22573 \param opacity Drawing opacity.
philpem@5 22574 \param pattern Drawing pattern.
philpem@5 22575 \param opacity_out Drawing opacity of 'outside' axes.
philpem@5 22576 \note if \c precision==0, precision of the labels is automatically computed.
philpem@5 22577 **/
philpem@5 22578 template<typename t, typename tc>
philpem@5 22579 CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
philpem@5 22580 const tc *const color, const float opacity=1,
philpem@5 22581 const unsigned int pattern=~0U) {
philpem@5 22582 if (!is_empty()) {
philpem@5 22583 int siz = (int)xvalues.size()-1;
philpem@5 22584 if (siz<=0) draw_line(0,y,width-1,y,color,opacity,pattern);
philpem@5 22585 else {
philpem@5 22586 if (xvalues[0]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,opacity,30,5,pattern);
philpem@5 22587 else draw_arrow(width-1,y,0,y,color,opacity,30,5,pattern);
philpem@5 22588 const int yt = (y+14)<dimy()?(y+3):(y-14);
philpem@5 22589 char txt[32];
philpem@5 22590 cimg_foroff(xvalues,x) {
philpem@5 22591 cimg_std::sprintf(txt,"%g",(double)xvalues(x));
philpem@5 22592 const int xi = (int)(x*(width-1)/siz), xt = xi-(int)cimg::strlen(txt)*3;
philpem@5 22593 draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity).
philpem@5 22594 draw_text(xt<0?0:xt,yt,txt,color,(tc*)0,opacity,11);
philpem@5 22595 }
philpem@5 22596 }
philpem@5 22597 }
philpem@5 22598 return *this;
philpem@5 22599 }
philpem@5 22600
philpem@5 22601 //! Draw a labeled horizontal axis on the instance image.
philpem@5 22602 template<typename t, typename tc>
philpem@5 22603 CImg<T>& draw_axis(const CImg<t>& xvalues, const int y,
philpem@5 22604 const CImg<tc>& color, const float opacity=1,
philpem@5 22605 const unsigned int pattern=~0U) {
philpem@5 22606 return draw_axis(xvalues,y,color.data,opacity,pattern);
philpem@5 22607 }
philpem@5 22608
philpem@5 22609 //! Draw a labeled vertical axis on the instance image.
philpem@5 22610 template<typename t, typename tc>
philpem@5 22611 CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
philpem@5 22612 const tc *const color, const float opacity=1,
philpem@5 22613 const unsigned int pattern=~0U) {
philpem@5 22614 if (!is_empty()) {
philpem@5 22615 int siz = (int)yvalues.size()-1;
philpem@5 22616 if (siz<=0) draw_line(x,0,x,height-1,color,opacity,pattern);
philpem@5 22617 else {
philpem@5 22618 if (yvalues[0]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,opacity,30,5,pattern);
philpem@5 22619 else draw_arrow(x,height-1,x,0,color,opacity,30,5,pattern);
philpem@5 22620 char txt[32];
philpem@5 22621 cimg_foroff(yvalues,y) {
philpem@5 22622 cimg_std::sprintf(txt,"%g",(double)yvalues(y));
philpem@5 22623 const int
philpem@5 22624 yi = (int)(y*(height-1)/siz),
philpem@5 22625 tmp = yi-5,
philpem@5 22626 nyi = tmp<0?0:(tmp>=dimy()-11?dimy()-11:tmp),
philpem@5 22627 xt = x-(int)cimg::strlen(txt)*7;
philpem@5 22628 draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity);
philpem@5 22629 if (xt>0) draw_text(xt,nyi,txt,color,(tc*)0,opacity,11);
philpem@5 22630 else draw_text(x+3,nyi,txt,color,(tc*)0,opacity,11);
philpem@5 22631 }
philpem@5 22632 }
philpem@5 22633 }
philpem@5 22634 return *this;
philpem@5 22635 }
philpem@5 22636
philpem@5 22637 //! Draw a labeled vertical axis on the instance image.
philpem@5 22638 template<typename t, typename tc>
philpem@5 22639 CImg<T>& draw_axis(const int x, const CImg<t>& yvalues,
philpem@5 22640 const CImg<tc>& color, const float opacity=1,
philpem@5 22641 const unsigned int pattern=~0U) {
philpem@5 22642 return draw_axis(x,yvalues,color.data,opacity,pattern);
philpem@5 22643 }
philpem@5 22644
philpem@5 22645 //! Draw a labeled horizontal+vertical axis on the instance image.
philpem@5 22646 template<typename tx, typename ty, typename tc>
philpem@5 22647 CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
philpem@5 22648 const tc *const color, const float opacity=1,
philpem@5 22649 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22650 if (!is_empty()) {
philpem@5 22651 const CImg<tx> nxvalues(xvalues.data,xvalues.size(),1,1,1,true);
philpem@5 22652 const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1;
philpem@5 22653 if (sizx>0) {
philpem@5 22654 float ox = (float)nxvalues[0];
philpem@5 22655 for (unsigned int x = 1; x<width; ++x) {
philpem@5 22656 const float nx = (float)nxvalues._linear_atX((float)x*sizx/wm1);
philpem@5 22657 if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,opacity,patterny); break; }
philpem@5 22658 ox = nx;
philpem@5 22659 }
philpem@5 22660 }
philpem@5 22661 const CImg<ty> nyvalues(yvalues.data,yvalues.size(),1,1,1,true);
philpem@5 22662 const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1;
philpem@5 22663 if (sizy>0) {
philpem@5 22664 float oy = (float)nyvalues[0];
philpem@5 22665 for (unsigned int y = 1; y<height; ++y) {
philpem@5 22666 const float ny = (float)nyvalues._linear_atX((float)y*sizy/hm1);
philpem@5 22667 if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,opacity,patternx); break; }
philpem@5 22668 oy = ny;
philpem@5 22669 }
philpem@5 22670 }
philpem@5 22671 }
philpem@5 22672 return *this;
philpem@5 22673 }
philpem@5 22674
philpem@5 22675 //! Draw a labeled horizontal+vertical axis on the instance image.
philpem@5 22676 template<typename tx, typename ty, typename tc>
philpem@5 22677 CImg<T>& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
philpem@5 22678 const CImg<tc>& color, const float opacity=1,
philpem@5 22679 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22680 return draw_axis(xvalues,yvalues,color.data,opacity,patternx,patterny);
philpem@5 22681 }
philpem@5 22682
philpem@5 22683 //! Draw a labeled horizontal+vertical axis on the instance image.
philpem@5 22684 template<typename tc>
philpem@5 22685 CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
philpem@5 22686 const tc *const color, const float opacity=1,
philpem@5 22687 const int subdivisionx=-60, const int subdivisiony=-60,
philpem@5 22688 const float precisionx=0, const float precisiony=0,
philpem@5 22689 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22690 if (!is_empty()) {
philpem@5 22691 const float
philpem@5 22692 dx = cimg::abs(x1-x0), dy = cimg::abs(y1-y0),
philpem@5 22693 px = (precisionx==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0):precisionx,
philpem@5 22694 py = (precisiony==0)?(float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0):precisiony;
philpem@5 22695 draw_axis(CImg<floatT>::sequence(subdivisionx>0?subdivisionx:1-dimx()/subdivisionx,x0,x1).round(px),
philpem@5 22696 CImg<floatT>::sequence(subdivisiony>0?subdivisiony:1-dimy()/subdivisiony,y0,y1).round(py),
philpem@5 22697 color,opacity,patternx,patterny);
philpem@5 22698 }
philpem@5 22699 return *this;
philpem@5 22700 }
philpem@5 22701
philpem@5 22702 //! Draw a labeled horizontal+vertical axis on the instance image.
philpem@5 22703 template<typename tc>
philpem@5 22704 CImg<T>& draw_axis(const float x0, const float x1, const float y0, const float y1,
philpem@5 22705 const CImg<tc>& color, const float opacity=1,
philpem@5 22706 const int subdivisionx=-60, const int subdivisiony=-60,
philpem@5 22707 const float precisionx=0, const float precisiony=0,
philpem@5 22708 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22709 return draw_axis(x0,x1,y0,y1,color.data,opacity,subdivisionx,subdivisiony,precisionx,precisiony,patternx,patterny);
philpem@5 22710 }
philpem@5 22711
philpem@5 22712 //! Draw grid.
philpem@5 22713 template<typename tx, typename ty, typename tc>
philpem@5 22714 CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
philpem@5 22715 const tc *const color, const float opacity=1,
philpem@5 22716 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22717 if (!is_empty()) {
philpem@5 22718 if (xvalues) cimg_foroff(xvalues,x) {
philpem@5 22719 const int xi = (int)xvalues[x];
philpem@5 22720 if (xi>=0 && xi<dimx()) draw_line(xi,0,xi,height-1,color,opacity,patternx);
philpem@5 22721 }
philpem@5 22722 if (yvalues) cimg_foroff(yvalues,y) {
philpem@5 22723 const int yi = (int)yvalues[y];
philpem@5 22724 if (yi>=0 && yi<dimy()) draw_line(0,yi,width-1,yi,color,opacity,patterny);
philpem@5 22725 }
philpem@5 22726 }
philpem@5 22727 return *this;
philpem@5 22728 }
philpem@5 22729
philpem@5 22730 //! Draw grid.
philpem@5 22731 template<typename tx, typename ty, typename tc>
philpem@5 22732 CImg<T>& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& yvalues,
philpem@5 22733 const CImg<tc>& color, const float opacity=1,
philpem@5 22734 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22735 return draw_grid(xvalues,yvalues,color.data,opacity,patternx,patterny);
philpem@5 22736 }
philpem@5 22737
philpem@5 22738 //! Draw grid.
philpem@5 22739 template<typename tc>
philpem@5 22740 CImg<T>& draw_grid(const float deltax, const float deltay,
philpem@5 22741 const float offsetx, const float offsety,
philpem@5 22742 const bool invertx, const bool inverty,
philpem@5 22743 const tc *const color, const float opacity=1,
philpem@5 22744 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22745 CImg<uintT> seqx, seqy;
philpem@5 22746 if (deltax!=0) {
philpem@5 22747 const float dx = deltax>0?deltax:width*-deltax/100;
philpem@5 22748 const unsigned int nx = (unsigned int)(width/dx);
philpem@5 22749 seqx = CImg<uintT>::sequence(1+nx,0,(unsigned int)(dx*nx));
philpem@5 22750 if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width);
philpem@5 22751 if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x);
philpem@5 22752 }
philpem@5 22753
philpem@5 22754 if (deltay!=0) {
philpem@5 22755 const float dy = deltay>0?deltay:height*-deltay/100;
philpem@5 22756 const unsigned int ny = (unsigned int)(height/dy);
philpem@5 22757 seqy = CImg<uintT>::sequence(1+ny,0,(unsigned int)(dy*ny));
philpem@5 22758 if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height);
philpem@5 22759 if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y);
philpem@5 22760 }
philpem@5 22761 return draw_grid(seqx,seqy,color,opacity,patternx,patterny);
philpem@5 22762 }
philpem@5 22763
philpem@5 22764 //! Draw grid.
philpem@5 22765 template<typename tc>
philpem@5 22766 CImg<T>& draw_grid(const float deltax, const float deltay,
philpem@5 22767 const float offsetx, const float offsety,
philpem@5 22768 const bool invertx, const bool inverty,
philpem@5 22769 const CImg<tc>& color, const float opacity=1,
philpem@5 22770 const unsigned int patternx=~0U, const unsigned int patterny=~0U) {
philpem@5 22771 return draw_grid(deltax,deltay,offsetx,offsety,invertx,inverty,color.data,opacity,patternx,patterny);
philpem@5 22772 }
philpem@5 22773
philpem@5 22774 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
philpem@5 22775 /**
philpem@5 22776 \param x X-coordinate of the starting point of the region to fill.
philpem@5 22777 \param y Y-coordinate of the starting point of the region to fill.
philpem@5 22778 \param z Z-coordinate of the starting point of the region to fill.
philpem@5 22779 \param color An array of dimv() values of type \c T, defining the drawing color.
philpem@5 22780 \param region Image that will contain the mask of the filled region mask, as an output.
philpem@5 22781 \param sigma Tolerance concerning neighborhood values.
philpem@5 22782 \param opacity Opacity of the drawing.
philpem@5 22783 \param high_connexity Tells if 8-connexity must be used (only for 2D images).
philpem@5 22784 \return \p region is initialized with the binary mask of the filled region.
philpem@5 22785 **/
philpem@5 22786 template<typename tc, typename t>
philpem@5 22787 CImg<T>& draw_fill(const int x, const int y, const int z,
philpem@5 22788 const tc *const color, const float opacity,
philpem@5 22789 CImg<t>& region, const float sigma=0,
philpem@5 22790 const bool high_connexity=false) {
philpem@5 22791
philpem@5 22792 #define _cimg_draw_fill_test(x,y,z,res) if (region(x,y,z)) res = false; else { \
philpem@5 22793 res = true; \
philpem@5 22794 const T *reference_col = reference_color.ptr() + dim, *ptrs = ptr(x,y,z) + siz; \
philpem@5 22795 for (unsigned int i = dim; res && i; --i) { ptrs-=whz; res = (cimg::abs(*ptrs - *(--reference_col))<=sigma); } \
philpem@5 22796 region(x,y,z) = (t)(res?1:noregion); \
philpem@5 22797 }
philpem@5 22798
philpem@5 22799 #define _cimg_draw_fill_set(x,y,z) { \
philpem@5 22800 const tc *col = color; \
philpem@5 22801 T *ptrd = ptr(x,y,z); \
philpem@5 22802 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)*(col++); ptrd+=whz; } \
philpem@5 22803 else cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } \
philpem@5 22804 }
philpem@5 22805
philpem@5 22806 #define _cimg_draw_fill_insert(x,y,z) { \
philpem@5 22807 if (posr1>=remaining.height) remaining.resize(3,remaining.height<<1,1,1,0); \
philpem@5 22808 unsigned int *ptrr = remaining.ptr(0,posr1); \
philpem@5 22809 *(ptrr++) = x; *(ptrr++) = y; *(ptrr++) = z; ++posr1; \
philpem@5 22810 }
philpem@5 22811
philpem@5 22812 #define _cimg_draw_fill_test_neighbor(x,y,z,cond) if (cond) { \
philpem@5 22813 const unsigned int tx = x, ty = y, tz = z; \
philpem@5 22814 _cimg_draw_fill_test(tx,ty,tz,res); if (res) _cimg_draw_fill_insert(tx,ty,tz); \
philpem@5 22815 }
philpem@5 22816
philpem@5 22817 if (!color)
philpem@5 22818 throw CImgArgumentException("CImg<%s>::draw_fill() : Specified color is (null).",
philpem@5 22819 pixel_type());
philpem@5 22820 region.assign(width,height,depth,1,(t)0);
philpem@5 22821 if (x>=0 && x<dimx() && y>=0 && y<dimy() && z>=0 && z<dimz()) {
philpem@5 22822 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 22823 const unsigned int whz = width*height*depth, siz = dim*whz, W1 = width-1, H1 = height-1, D1 = depth-1;
philpem@5 22824 const bool threed = depth>1;
philpem@5 22825 const CImg<T> reference_color = get_vector_at(x,y,z);
philpem@5 22826 CImg<uintT> remaining(3,512,1,1,0);
philpem@5 22827 remaining(0,0) = x; remaining(1,0) = y; remaining(2,0) = z;
philpem@5 22828 unsigned int posr0 = 0, posr1 = 1;
philpem@5 22829 region(x,y,z) = (t)1;
philpem@5 22830 const t noregion = ((t)1==(t)2)?(t)0:(t)(-1);
philpem@5 22831 if (threed) do { // 3D version of the filling algorithm
philpem@5 22832 const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++), zc = *(pcurr++);
philpem@5 22833 if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
philpem@5 22834 bool cont, res;
philpem@5 22835 unsigned int nxc = xc;
philpem@5 22836 do { // X-backward
philpem@5 22837 _cimg_draw_fill_set(nxc,yc,zc);
philpem@5 22838 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
philpem@5 22839 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
philpem@5 22840 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
philpem@5 22841 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
philpem@5 22842 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
philpem@5 22843 } while (cont);
philpem@5 22844 nxc = xc;
philpem@5 22845 do { // X-forward
philpem@5 22846 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,zc,cont); } else cont = false;
philpem@5 22847 if (cont) {
philpem@5 22848 _cimg_draw_fill_set(nxc,yc,zc);
philpem@5 22849 _cimg_draw_fill_test_neighbor(nxc,yc-1,zc,yc!=0);
philpem@5 22850 _cimg_draw_fill_test_neighbor(nxc,yc+1,zc,yc<H1);
philpem@5 22851 _cimg_draw_fill_test_neighbor(nxc,yc,zc-1,zc!=0);
philpem@5 22852 _cimg_draw_fill_test_neighbor(nxc,yc,zc+1,zc<D1);
philpem@5 22853 }
philpem@5 22854 } while (cont);
philpem@5 22855 unsigned int nyc = yc;
philpem@5 22856 do { // Y-backward
philpem@5 22857 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
philpem@5 22858 if (cont) {
philpem@5 22859 _cimg_draw_fill_set(xc,nyc,zc);
philpem@5 22860 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
philpem@5 22861 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
philpem@5 22862 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
philpem@5 22863 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
philpem@5 22864 }
philpem@5 22865 } while (cont);
philpem@5 22866 nyc = yc;
philpem@5 22867 do { // Y-forward
philpem@5 22868 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,zc,cont); } else cont = false;
philpem@5 22869 if (cont) {
philpem@5 22870 _cimg_draw_fill_set(xc,nyc,zc);
philpem@5 22871 _cimg_draw_fill_test_neighbor(xc-1,nyc,zc,xc!=0);
philpem@5 22872 _cimg_draw_fill_test_neighbor(xc+1,nyc,zc,xc<W1);
philpem@5 22873 _cimg_draw_fill_test_neighbor(xc,nyc,zc-1,zc!=0);
philpem@5 22874 _cimg_draw_fill_test_neighbor(xc,nyc,zc+1,zc<D1);
philpem@5 22875 }
philpem@5 22876 } while (cont);
philpem@5 22877 unsigned int nzc = zc;
philpem@5 22878 do { // Z-backward
philpem@5 22879 if (nzc) { --nzc; _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
philpem@5 22880 if (cont) {
philpem@5 22881 _cimg_draw_fill_set(xc,yc,nzc);
philpem@5 22882 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
philpem@5 22883 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
philpem@5 22884 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
philpem@5 22885 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
philpem@5 22886 }
philpem@5 22887 } while (cont);
philpem@5 22888 nzc = zc;
philpem@5 22889 do { // Z-forward
philpem@5 22890 if ((++nzc)<=D1) { _cimg_draw_fill_test(xc,yc,nzc,cont); } else cont = false;
philpem@5 22891 if (cont) {
philpem@5 22892 _cimg_draw_fill_set(xc,nyc,zc);
philpem@5 22893 _cimg_draw_fill_test_neighbor(xc-1,yc,nzc,xc!=0);
philpem@5 22894 _cimg_draw_fill_test_neighbor(xc+1,yc,nzc,xc<W1);
philpem@5 22895 _cimg_draw_fill_test_neighbor(xc,yc-1,nzc,yc!=0);
philpem@5 22896 _cimg_draw_fill_test_neighbor(xc,yc+1,nzc,yc<H1);
philpem@5 22897 }
philpem@5 22898 } while (cont);
philpem@5 22899 } while (posr1>posr0);
philpem@5 22900 else do { // 2D version of the filling algorithm
philpem@5 22901 const unsigned int *pcurr = remaining.ptr(0,posr0++), xc = *(pcurr++), yc = *(pcurr++);
philpem@5 22902 if (posr0>=512) { remaining.translate(0,posr0); posr1-=posr0; posr0 = 0; }
philpem@5 22903 bool cont, res;
philpem@5 22904 unsigned int nxc = xc;
philpem@5 22905 do { // X-backward
philpem@5 22906 _cimg_draw_fill_set(nxc,yc,0);
philpem@5 22907 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
philpem@5 22908 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
philpem@5 22909 if (high_connexity) {
philpem@5 22910 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
philpem@5 22911 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
philpem@5 22912 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
philpem@5 22913 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
philpem@5 22914 }
philpem@5 22915 if (nxc) { --nxc; _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
philpem@5 22916 } while (cont);
philpem@5 22917 nxc = xc;
philpem@5 22918 do { // X-forward
philpem@5 22919 if ((++nxc)<=W1) { _cimg_draw_fill_test(nxc,yc,0,cont); } else cont = false;
philpem@5 22920 if (cont) {
philpem@5 22921 _cimg_draw_fill_set(nxc,yc,0);
philpem@5 22922 _cimg_draw_fill_test_neighbor(nxc,yc-1,0,yc!=0);
philpem@5 22923 _cimg_draw_fill_test_neighbor(nxc,yc+1,0,yc<H1);
philpem@5 22924 if (high_connexity) {
philpem@5 22925 _cimg_draw_fill_test_neighbor(nxc-1,yc-1,0,(nxc!=0 && yc!=0));
philpem@5 22926 _cimg_draw_fill_test_neighbor(nxc+1,yc-1,0,(nxc<W1 && yc!=0));
philpem@5 22927 _cimg_draw_fill_test_neighbor(nxc-1,yc+1,0,(nxc!=0 && yc<H1));
philpem@5 22928 _cimg_draw_fill_test_neighbor(nxc+1,yc+1,0,(nxc<W1 && yc<H1));
philpem@5 22929 }
philpem@5 22930 }
philpem@5 22931 } while (cont);
philpem@5 22932 unsigned int nyc = yc;
philpem@5 22933 do { // Y-backward
philpem@5 22934 if (nyc) { --nyc; _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
philpem@5 22935 if (cont) {
philpem@5 22936 _cimg_draw_fill_set(xc,nyc,0);
philpem@5 22937 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
philpem@5 22938 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
philpem@5 22939 if (high_connexity) {
philpem@5 22940 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
philpem@5 22941 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
philpem@5 22942 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
philpem@5 22943 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
philpem@5 22944 }
philpem@5 22945 }
philpem@5 22946 } while (cont);
philpem@5 22947 nyc = yc;
philpem@5 22948 do { // Y-forward
philpem@5 22949 if ((++nyc)<=H1) { _cimg_draw_fill_test(xc,nyc,0,cont); } else cont = false;
philpem@5 22950 if (cont) {
philpem@5 22951 _cimg_draw_fill_set(xc,nyc,0);
philpem@5 22952 _cimg_draw_fill_test_neighbor(xc-1,nyc,0,xc!=0);
philpem@5 22953 _cimg_draw_fill_test_neighbor(xc+1,nyc,0,xc<W1);
philpem@5 22954 if (high_connexity) {
philpem@5 22955 _cimg_draw_fill_test_neighbor(xc-1,nyc-1,0,(xc!=0 && nyc!=0));
philpem@5 22956 _cimg_draw_fill_test_neighbor(xc+1,nyc-1,0,(xc<W1 && nyc!=0));
philpem@5 22957 _cimg_draw_fill_test_neighbor(xc-1,nyc+1,0,(xc!=0 && nyc<H1));
philpem@5 22958 _cimg_draw_fill_test_neighbor(xc+1,nyc+1,0,(xc<W1 && nyc<H1));
philpem@5 22959 }
philpem@5 22960 }
philpem@5 22961 } while (cont);
philpem@5 22962 } while (posr1>posr0);
philpem@5 22963 if (noregion) cimg_for(region,ptr,t) if (*ptr==noregion) *ptr = (t)0;
philpem@5 22964 }
philpem@5 22965 return *this;
philpem@5 22966 }
philpem@5 22967
philpem@5 22968 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
philpem@5 22969 template<typename tc, typename t>
philpem@5 22970 CImg<T>& draw_fill(const int x, const int y, const int z,
philpem@5 22971 const CImg<tc>& color, const float opacity,
philpem@5 22972 CImg<t>& region, const float sigma=0, const bool high_connexity=false) {
philpem@5 22973 return draw_fill(x,y,z,color.data,opacity,region,sigma,high_connexity);
philpem@5 22974 }
philpem@5 22975
philpem@5 22976 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
philpem@5 22977 /**
philpem@5 22978 \param x = X-coordinate of the starting point of the region to fill.
philpem@5 22979 \param y = Y-coordinate of the starting point of the region to fill.
philpem@5 22980 \param z = Z-coordinate of the starting point of the region to fill.
philpem@5 22981 \param color = an array of dimv() values of type \c T, defining the drawing color.
philpem@5 22982 \param sigma = tolerance concerning neighborhood values.
philpem@5 22983 \param opacity = opacity of the drawing.
philpem@5 22984 **/
philpem@5 22985 template<typename tc>
philpem@5 22986 CImg<T>& draw_fill(const int x, const int y, const int z,
philpem@5 22987 const tc *const color, const float opacity=1,
philpem@5 22988 const float sigma=0, const bool high_connexity=false) {
philpem@5 22989 CImg<boolT> tmp;
philpem@5 22990 return draw_fill(x,y,z,color,opacity,tmp,sigma,high_connexity);
philpem@5 22991 }
philpem@5 22992
philpem@5 22993 //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image.
philpem@5 22994 template<typename tc>
philpem@5 22995 CImg<T>& draw_fill(const int x, const int y, const int z,
philpem@5 22996 const CImg<tc>& color, const float opacity=1,
philpem@5 22997 const float sigma=0, const bool high_connexity=false) {
philpem@5 22998 return draw_fill(x,y,z,color.data,opacity,sigma,high_connexity);
philpem@5 22999 }
philpem@5 23000
philpem@5 23001 //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
philpem@5 23002 /**
philpem@5 23003 \param x = X-coordinate of the starting point of the region to fill.
philpem@5 23004 \param y = Y-coordinate of the starting point of the region to fill.
philpem@5 23005 \param color = an array of dimv() values of type \c T, defining the drawing color.
philpem@5 23006 \param sigma = tolerance concerning neighborhood values.
philpem@5 23007 \param opacity = opacity of the drawing.
philpem@5 23008 **/
philpem@5 23009 template<typename tc>
philpem@5 23010 CImg<T>& draw_fill(const int x, const int y,
philpem@5 23011 const tc *const color, const float opacity=1,
philpem@5 23012 const float sigma=0, const bool high_connexity=false) {
philpem@5 23013 CImg<boolT> tmp;
philpem@5 23014 return draw_fill(x,y,0,color,opacity,tmp,sigma,high_connexity);
philpem@5 23015 }
philpem@5 23016
philpem@5 23017 //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image.
philpem@5 23018 template<typename tc>
philpem@5 23019 CImg<T>& draw_fill(const int x, const int y,
philpem@5 23020 const CImg<tc>& color, const float opacity=1,
philpem@5 23021 const float sigma=0, const bool high_connexity=false) {
philpem@5 23022 return draw_fill(x,y,color.data,opacity,sigma,high_connexity);
philpem@5 23023 }
philpem@5 23024
philpem@5 23025 //! Draw a plasma random texture.
philpem@5 23026 /**
philpem@5 23027 \param x0 = X-coordinate of the upper-left corner of the plasma.
philpem@5 23028 \param y0 = Y-coordinate of the upper-left corner of the plasma.
philpem@5 23029 \param x1 = X-coordinate of the lower-right corner of the plasma.
philpem@5 23030 \param y1 = Y-coordinate of the lower-right corner of the plasma.
philpem@5 23031 \param alpha = Alpha-parameter of the plasma.
philpem@5 23032 \param beta = Beta-parameter of the plasma.
philpem@5 23033 \param opacity = opacity of the drawing.
philpem@5 23034 **/
philpem@5 23035 CImg<T>& draw_plasma(const int x0, const int y0, const int x1, const int y1,
philpem@5 23036 const float alpha=1, const float beta=1,
philpem@5 23037 const float opacity=1) {
philpem@5 23038 if (!is_empty()) {
philpem@5 23039 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 23040 int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1;
philpem@5 23041 if (nx1<nx0) cimg::swap(nx0,nx1);
philpem@5 23042 if (ny1<ny0) cimg::swap(ny0,ny1);
philpem@5 23043 if (nx0<0) nx0 = 0;
philpem@5 23044 if (nx1>=dimx()) nx1 = width-1;
philpem@5 23045 if (ny0<0) ny0 = 0;
philpem@5 23046 if (ny1>=dimy()) ny1 = height-1;
philpem@5 23047 const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx = (xc-nx0), dy = (yc-ny0);
philpem@5 23048 const Tfloat dc = (Tfloat)(cimg_std::sqrt((float)(dx*dx+dy*dy))*alpha + beta);
philpem@5 23049 Tfloat val = 0;
philpem@5 23050 cimg_forV(*this,k) {
philpem@5 23051 if (opacity>=1) {
philpem@5 23052 const Tfloat
philpem@5 23053 val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
philpem@5 23054 val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
philpem@5 23055 (*this)(xc,ny0,0,k) = (T)((val0+val1)/2);
philpem@5 23056 (*this)(xc,ny1,0,k) = (T)((val2+val3)/2);
philpem@5 23057 (*this)(nx0,yc,0,k) = (T)((val0+val2)/2);
philpem@5 23058 (*this)(nx1,yc,0,k) = (T)((val1+val3)/2);
philpem@5 23059 do {
philpem@5 23060 val = (Tfloat)(0.25f*((Tfloat)((*this)(nx0,ny0,0,k)) +
philpem@5 23061 (Tfloat)((*this)(nx1,ny0,0,k)) +
philpem@5 23062 (Tfloat)((*this)(nx1,ny1,0,k)) +
philpem@5 23063 (Tfloat)((*this)(nx0,ny1,0,k))) +
philpem@5 23064 dc*cimg::grand());
philpem@5 23065 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
philpem@5 23066 (*this)(xc,yc,0,k) = (T)val;
philpem@5 23067 } else {
philpem@5 23068 const Tfloat
philpem@5 23069 val0 = (Tfloat)((*this)(nx0,ny0,0,k)), val1 = (Tfloat)((*this)(nx1,ny0,0,k)),
philpem@5 23070 val2 = (Tfloat)((*this)(nx0,ny1,0,k)), val3 = (Tfloat)((*this)(nx1,ny1,0,k));
philpem@5 23071 (*this)(xc,ny0,0,k) = (T)(((val0+val1)*nopacity + copacity*(*this)(xc,ny0,0,k))/2);
philpem@5 23072 (*this)(xc,ny1,0,k) = (T)(((val2+val3)*nopacity + copacity*(*this)(xc,ny1,0,k))/2);
philpem@5 23073 (*this)(nx0,yc,0,k) = (T)(((val0+val2)*nopacity + copacity*(*this)(nx0,yc,0,k))/2);
philpem@5 23074 (*this)(nx1,yc,0,k) = (T)(((val1+val3)*nopacity + copacity*(*this)(nx1,yc,0,k))/2);
philpem@5 23075 do {
philpem@5 23076 val = (Tfloat)(0.25f*(((Tfloat)((*this)(nx0,ny0,0,k)) +
philpem@5 23077 (Tfloat)((*this)(nx1,ny0,0,k)) +
philpem@5 23078 (Tfloat)((*this)(nx1,ny1,0,k)) +
philpem@5 23079 (Tfloat)((*this)(nx0,ny1,0,k))) +
philpem@5 23080 dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k));
philpem@5 23081 } while (val<(Tfloat)cimg::type<T>::min() || val>(Tfloat)cimg::type<T>::max());
philpem@5 23082 (*this)(xc,yc,0,k) = (T)val;
philpem@5 23083 }
philpem@5 23084 }
philpem@5 23085 if (xc!=nx0 || yc!=ny0) {
philpem@5 23086 draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity);
philpem@5 23087 draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity);
philpem@5 23088 draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity);
philpem@5 23089 draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity);
philpem@5 23090 }
philpem@5 23091 }
philpem@5 23092 return *this;
philpem@5 23093 }
philpem@5 23094
philpem@5 23095 //! Draw a plasma random texture.
philpem@5 23096 /**
philpem@5 23097 \param alpha = Alpha-parameter of the plasma.
philpem@5 23098 \param beta = Beta-parameter of the plasma.
philpem@5 23099 \param opacity = opacity of the drawing.
philpem@5 23100 **/
philpem@5 23101 CImg<T>& draw_plasma(const float alpha=1, const float beta=1,
philpem@5 23102 const float opacity=1) {
philpem@5 23103 return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity);
philpem@5 23104 }
philpem@5 23105
philpem@5 23106 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
philpem@5 23107 template<typename tc>
philpem@5 23108 CImg<T>& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1,
philpem@5 23109 const CImg<tc>& color_palette, const float opacity=1,
philpem@5 23110 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
philpem@5 23111 const unsigned int itermax=255,
philpem@5 23112 const bool normalized_iteration=false,
philpem@5 23113 const bool julia_set=false,
philpem@5 23114 const double paramr=0, const double parami=0) {
philpem@5 23115 if (is_empty()) return *this;
philpem@5 23116 CImg<tc> palette;
philpem@5 23117 if (color_palette) palette.assign(color_palette.data,color_palette.size()/color_palette.dim,1,1,color_palette.dim,true);
philpem@5 23118 if (palette && palette.dim!=dim)
philpem@5 23119 throw CImgArgumentException("CImg<%s>::draw_mandelbrot() : Specified color palette (%u,%u,%u,%u,%p) is not \n"
philpem@5 23120 "compatible with instance image (%u,%u,%u,%u,%p).",
philpem@5 23121 pixel_type(),color_palette.width,color_palette.height,color_palette.depth,color_palette.dim,
philpem@5 23122 color_palette.data,width,height,depth,dim,data);
philpem@5 23123 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0), ln2 = (float)cimg_std::log(2.0);
philpem@5 23124 unsigned int iter = 0;
philpem@5 23125 cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
philpem@5 23126 const double x = z0r + p*(z1r-z0r)/width, y = z0i + q*(z1i-z0i)/height;
philpem@5 23127 double zr, zi, cr, ci;
philpem@5 23128 if (julia_set) { zr = x; zi = y; cr = paramr; ci = parami; }
philpem@5 23129 else { zr = paramr; zi = parami; cr = x; ci = y; }
philpem@5 23130 for (iter=1; zr*zr + zi*zi<=4 && iter<=itermax; ++iter) {
philpem@5 23131 const double temp = zr*zr - zi*zi + cr;
philpem@5 23132 zi = 2*zr*zi + ci;
philpem@5 23133 zr = temp;
philpem@5 23134 }
philpem@5 23135 if (iter>itermax) {
philpem@5 23136 if (palette) {
philpem@5 23137 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette(0,k);
philpem@5 23138 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(0,k)*nopacity + (*this)(p,q,0,k)*copacity);
philpem@5 23139 } else {
philpem@5 23140 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)0;
philpem@5 23141 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)((*this)(p,q,0,k)*copacity);
philpem@5 23142 }
philpem@5 23143 } else if (normalized_iteration) {
philpem@5 23144 const float
philpem@5 23145 normz = (float)cimg::abs(zr*zr+zi*zi),
philpem@5 23146 niter = (float)(iter + 1 - cimg_std::log(cimg_std::log(normz))/ln2);
philpem@5 23147 if (palette) {
philpem@5 23148 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._linear_atX(niter,k);
philpem@5 23149 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette._linear_atX(niter,k)*nopacity + (*this)(p,q,0,k)*copacity);
philpem@5 23150 } else {
philpem@5 23151 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)niter;
philpem@5 23152 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(niter*nopacity + (*this)(p,q,0,k)*copacity);
philpem@5 23153 }
philpem@5 23154 } else {
philpem@5 23155 if (palette) {
philpem@5 23156 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)palette._atX(iter,k);
philpem@5 23157 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(palette(iter,k)*nopacity + (*this)(p,q,0,k)*copacity);
philpem@5 23158 } else {
philpem@5 23159 if (opacity>=1) cimg_forV(*this,k) (*this)(p,q,0,k) = (T)iter;
philpem@5 23160 else cimg_forV(*this,k) (*this)(p,q,0,k) = (T)(iter*nopacity + (*this)(p,q,0,k)*copacity);
philpem@5 23161 }
philpem@5 23162 }
philpem@5 23163 }
philpem@5 23164 return *this;
philpem@5 23165 }
philpem@5 23166
philpem@5 23167 //! Draw a quadratic Mandelbrot or Julia fractal set, computed using the Escape Time Algorithm.
philpem@5 23168 template<typename tc>
philpem@5 23169 CImg<T>& draw_mandelbrot(const CImg<tc>& color_palette, const float opacity=1,
philpem@5 23170 const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2,
philpem@5 23171 const unsigned int itermax=255,
philpem@5 23172 const bool normalized_iteration=false,
philpem@5 23173 const bool julia_set=false,
philpem@5 23174 const double paramr=0, const double parami=0) {
philpem@5 23175 return draw_mandelbrot(0,0,width-1,height-1,color_palette,opacity,z0r,z0i,z1r,z1i,itermax,normalized_iteration,julia_set,paramr,parami);
philpem@5 23176 }
philpem@5 23177
philpem@5 23178 //! Draw a 1D gaussian function in the instance image.
philpem@5 23179 /**
philpem@5 23180 \param xc = X-coordinate of the gaussian center.
philpem@5 23181 \param sigma = Standard variation of the gaussian distribution.
philpem@5 23182 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 23183 \param opacity = opacity of the drawing.
philpem@5 23184 **/
philpem@5 23185 template<typename tc>
philpem@5 23186 CImg<T>& draw_gaussian(const float xc, const float sigma,
philpem@5 23187 const tc *const color, const float opacity=1) {
philpem@5 23188 if (is_empty()) return *this;
philpem@5 23189 if (!color)
philpem@5 23190 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
philpem@5 23191 pixel_type());
philpem@5 23192 const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 23193 const unsigned int whz = width*height*depth;
philpem@5 23194 const tc *col = color;
philpem@5 23195 cimg_forX(*this,x) {
philpem@5 23196 const float dx = (x - xc), val = (float)cimg_std::exp(-dx*dx/sigma2);
philpem@5 23197 T *ptrd = ptr(x,0,0,0);
philpem@5 23198 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
philpem@5 23199 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
philpem@5 23200 col-=dim;
philpem@5 23201 }
philpem@5 23202 return *this;
philpem@5 23203 }
philpem@5 23204
philpem@5 23205 //! Draw a 1D gaussian function in the instance image.
philpem@5 23206 template<typename tc>
philpem@5 23207 CImg<T>& draw_gaussian(const float xc, const float sigma,
philpem@5 23208 const CImg<tc>& color, const float opacity=1) {
philpem@5 23209 return draw_gaussian(xc,sigma,color.data,opacity);
philpem@5 23210 }
philpem@5 23211
philpem@5 23212 //! Draw an anisotropic 2D gaussian function.
philpem@5 23213 /**
philpem@5 23214 \param xc = X-coordinate of the gaussian center.
philpem@5 23215 \param yc = Y-coordinate of the gaussian center.
philpem@5 23216 \param tensor = 2x2 covariance matrix.
philpem@5 23217 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 23218 \param opacity = opacity of the drawing.
philpem@5 23219 **/
philpem@5 23220 template<typename t, typename tc>
philpem@5 23221 CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
philpem@5 23222 const tc *const color, const float opacity=1) {
philpem@5 23223 if (is_empty()) return *this;
philpem@5 23224 typedef typename cimg::superset<t,float>::type tfloat;
philpem@5 23225 if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1)
philpem@5 23226 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.",
philpem@5 23227 pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
philpem@5 23228 if (!color)
philpem@5 23229 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",
philpem@5 23230 pixel_type());
philpem@5 23231 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
philpem@5 23232 const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1);
philpem@5 23233 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 23234 const unsigned int whz = width*height*depth;
philpem@5 23235 const tc *col = color;
philpem@5 23236 float dy = -yc;
philpem@5 23237 cimg_forY(*this,y) {
philpem@5 23238 float dx = -xc;
philpem@5 23239 cimg_forX(*this,x) {
philpem@5 23240 const float val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dy*dy);
philpem@5 23241 T *ptrd = ptr(x,y,0,0);
philpem@5 23242 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
philpem@5 23243 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
philpem@5 23244 col-=dim;
philpem@5 23245 ++dx;
philpem@5 23246 }
philpem@5 23247 ++dy;
philpem@5 23248 }
philpem@5 23249 return *this;
philpem@5 23250 }
philpem@5 23251
philpem@5 23252 //! Draw an anisotropic 2D gaussian function.
philpem@5 23253 template<typename t, typename tc>
philpem@5 23254 CImg<T>& draw_gaussian(const float xc, const float yc, const CImg<t>& tensor,
philpem@5 23255 const CImg<tc>& color, const float opacity=1) {
philpem@5 23256 return draw_gaussian(xc,yc,tensor,color.data,opacity);
philpem@5 23257 }
philpem@5 23258
philpem@5 23259 //! Draw an anisotropic 2D gaussian function.
philpem@5 23260 template<typename tc>
philpem@5 23261 CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
philpem@5 23262 const tc *const color, const float opacity=1) {
philpem@5 23263 const double
philpem@5 23264 a = r1*ru*ru + r2*rv*rv,
philpem@5 23265 b = (r1-r2)*ru*rv,
philpem@5 23266 c = r1*rv*rv + r2*ru*ru;
philpem@5 23267 const CImg<Tfloat> tensor(2,2,1,1, a,b,b,c);
philpem@5 23268 return draw_gaussian(xc,yc,tensor,color,opacity);
philpem@5 23269 }
philpem@5 23270
philpem@5 23271 //! Draw an anisotropic 2D gaussian function.
philpem@5 23272 template<typename tc>
philpem@5 23273 CImg<T>& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv,
philpem@5 23274 const CImg<tc>& color, const float opacity=1) {
philpem@5 23275 return draw_gaussian(xc,yc,r1,r2,ru,rv,color.data,opacity);
philpem@5 23276 }
philpem@5 23277
philpem@5 23278 //! Draw an isotropic 2D gaussian function.
philpem@5 23279 /**
philpem@5 23280 \param xc = X-coordinate of the gaussian center.
philpem@5 23281 \param yc = Y-coordinate of the gaussian center.
philpem@5 23282 \param sigma = standard variation of the gaussian distribution.
philpem@5 23283 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 23284 \param opacity = opacity of the drawing.
philpem@5 23285 **/
philpem@5 23286 template<typename tc>
philpem@5 23287 CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
philpem@5 23288 const tc *const color, const float opacity=1) {
philpem@5 23289 return draw_gaussian(xc,yc,CImg<floatT>::diagonal(sigma,sigma),color,opacity);
philpem@5 23290 }
philpem@5 23291
philpem@5 23292 //! Draw an isotropic 2D gaussian function.
philpem@5 23293 template<typename tc>
philpem@5 23294 CImg<T>& draw_gaussian(const float xc, const float yc, const float sigma,
philpem@5 23295 const CImg<tc>& color, const float opacity=1) {
philpem@5 23296 return draw_gaussian(xc,yc,sigma,color.data,opacity);
philpem@5 23297 }
philpem@5 23298
philpem@5 23299 //! Draw an anisotropic 3D gaussian function.
philpem@5 23300 /**
philpem@5 23301 \param xc = X-coordinate of the gaussian center.
philpem@5 23302 \param yc = Y-coordinate of the gaussian center.
philpem@5 23303 \param zc = Z-coordinate of the gaussian center.
philpem@5 23304 \param tensor = 3x3 covariance matrix.
philpem@5 23305 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 23306 \param opacity = opacity of the drawing.
philpem@5 23307 **/
philpem@5 23308 template<typename t, typename tc>
philpem@5 23309 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
philpem@5 23310 const tc *const color, const float opacity=1) {
philpem@5 23311 if (is_empty()) return *this;
philpem@5 23312 typedef typename cimg::superset<t,float>::type tfloat;
philpem@5 23313 if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1)
philpem@5 23314 throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.",
philpem@5 23315 pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data);
philpem@5 23316 const CImg<tfloat> invT = tensor.get_invert(), invT2 = (invT*invT)/(-2.0);
philpem@5 23317 const tfloat a = invT(0,0), b = 2*invT(1,0), c = 2*invT(2,0), d = invT(1,1), e = 2*invT(2,1), f = invT(2,2);
philpem@5 23318 const float nopacity = cimg::abs(opacity), copacity = 1 - cimg::max(opacity,0);
philpem@5 23319 const unsigned int whz = width*height*depth;
philpem@5 23320 const tc *col = color;
philpem@5 23321 cimg_forXYZ(*this,x,y,z) {
philpem@5 23322 const float
philpem@5 23323 dx = (x - xc), dy = (y - yc), dz = (z - zc),
philpem@5 23324 val = (float)cimg_std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz);
philpem@5 23325 T *ptrd = ptr(x,y,z,0);
philpem@5 23326 if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; }
philpem@5 23327 else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whz; }
philpem@5 23328 col-=dim;
philpem@5 23329 }
philpem@5 23330 return *this;
philpem@5 23331 }
philpem@5 23332
philpem@5 23333 //! Draw an anisotropic 3D gaussian function.
philpem@5 23334 template<typename t, typename tc>
philpem@5 23335 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const CImg<t>& tensor,
philpem@5 23336 const CImg<tc>& color, const float opacity=1) {
philpem@5 23337 return draw_gaussian(xc,yc,zc,tensor,color.data,opacity);
philpem@5 23338 }
philpem@5 23339
philpem@5 23340 //! Draw an isotropic 3D gaussian function.
philpem@5 23341 /**
philpem@5 23342 \param xc = X-coordinate of the gaussian center.
philpem@5 23343 \param yc = Y-coordinate of the gaussian center.
philpem@5 23344 \param zc = Z-coordinate of the gaussian center.
philpem@5 23345 \param sigma = standard variation of the gaussian distribution.
philpem@5 23346 \param color = array of dimv() values of type \c T, defining the drawing color.
philpem@5 23347 \param opacity = opacity of the drawing.
philpem@5 23348 **/
philpem@5 23349 template<typename tc>
philpem@5 23350 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
philpem@5 23351 const tc *const color, const float opacity=1) {
philpem@5 23352 return draw_gaussian(xc,yc,zc,CImg<floatT>::diagonal(sigma,sigma,sigma),color,opacity);
philpem@5 23353 }
philpem@5 23354
philpem@5 23355 //! Draw an isotropic 3D gaussian function.
philpem@5 23356 template<typename tc>
philpem@5 23357 CImg<T>& draw_gaussian(const float xc, const float yc, const float zc, const float sigma,
philpem@5 23358 const CImg<tc>& color, const float opacity=1) {
philpem@5 23359 return draw_gaussian(xc,yc,zc,sigma,color.data,opacity);
philpem@5 23360 }
philpem@5 23361
philpem@5 23362 // Draw a 3D object (internal)
philpem@5 23363 template<typename tc, typename to>
philpem@5 23364 void _draw_object3d_sprite(const int x, const int y,
philpem@5 23365 const CImg<tc>& color, const CImg<to>& opacity, const CImg<T>& sprite) {
philpem@5 23366 if (opacity.width==color.width && opacity.height==color.height)
philpem@5 23367 draw_image(x,y,sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1));
philpem@5 23368 else
philpem@5 23369 draw_image(x,y,sprite,opacity(0));
philpem@5 23370 }
philpem@5 23371
philpem@5 23372 template<typename tc>
philpem@5 23373 void _draw_object3d_sprite(const int x, const int y,
philpem@5 23374 const CImg<tc>& color, const float opacity, const CImg<T>& sprite) {
philpem@5 23375 if (color) draw_image(x,y,sprite,opacity);
philpem@5 23376 }
philpem@5 23377
philpem@5 23378 template<typename tp, typename tf, typename tc, typename to>
philpem@5 23379 CImg<T>& _draw_object3d(void *const pboard, float *const zbuffer,
philpem@5 23380 const float X, const float Y, const float Z,
philpem@5 23381 const tp& points, const unsigned int nb_points,
philpem@5 23382 const CImgList<tf>& primitives,
philpem@5 23383 const CImgList<tc>& colors,
philpem@5 23384 const to& opacities, const unsigned int nb_opacities,
philpem@5 23385 const unsigned int render_type,
philpem@5 23386 const bool double_sided, const float focale,
philpem@5 23387 const float lightx, const float lighty, const float lightz,
philpem@5 23388 const float specular_light, const float specular_shine) {
philpem@5 23389 if (is_empty()) return *this;
philpem@5 23390 #ifndef cimg_use_board
philpem@5 23391 if (pboard) return *this;
philpem@5 23392 #endif
philpem@5 23393 const float
philpem@5 23394 nspec = 1-(specular_light<0?0:(specular_light>1?1:specular_light)),
philpem@5 23395 nspec2 = 1+(specular_shine<0?0:specular_shine),
philpem@5 23396 nsl1 = (nspec2-1)/cimg::sqr(nspec-1),
philpem@5 23397 nsl2 = (1-2*nsl1*nspec),
philpem@5 23398 nsl3 = nspec2-nsl1-nsl2;
philpem@5 23399
philpem@5 23400 // Create light texture for phong-like rendering
philpem@5 23401 static CImg<floatT> light_texture;
philpem@5 23402 if (render_type==5) {
philpem@5 23403 if (colors.size>primitives.size) light_texture.assign(colors[primitives.size])/=255;
philpem@5 23404 else {
philpem@5 23405 static float olightx = 0, olighty = 0, olightz = 0, ospecular_shine = 0;
philpem@5 23406 if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || specular_shine!=ospecular_shine) {
philpem@5 23407 light_texture.assign(512,512);
philpem@5 23408 const float white[] = { 1 },
philpem@5 23409 dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z,
philpem@5 23410 nl = (float)cimg_std::sqrt(dlx*dlx+dly*dly+dlz*dlz),
philpem@5 23411 nlx = light_texture.width/2*(1+dlx/nl),
philpem@5 23412 nly = light_texture.height/2*(1+dly/nl);
philpem@5 23413 light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white);
philpem@5 23414 cimg_forXY(light_texture,x,y) {
philpem@5 23415 const float factor = light_texture(x,y);
philpem@5 23416 if (factor>nspec) light_texture(x,y) = cimg::min(2,nsl1*factor*factor+nsl2*factor+nsl3);
philpem@5 23417 }
philpem@5 23418 olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shine = specular_shine;
philpem@5 23419 }
philpem@5 23420 }
philpem@5 23421 }
philpem@5 23422
philpem@5 23423 // Compute 3D to 2D projection
philpem@5 23424 CImg<floatT> projections(nb_points,2);
philpem@5 23425 cimg_forX(projections,l) {
philpem@5 23426 const float
philpem@5 23427 x = (float)points(l,0),
philpem@5 23428 y = (float)points(l,1),
philpem@5 23429 z = (float)points(l,2);
philpem@5 23430 const float projectedz = z + Z + focale;
philpem@5 23431 projections(l,1) = Y + focale*y/projectedz;
philpem@5 23432 projections(l,0) = X + focale*x/projectedz;
philpem@5 23433 }
philpem@5 23434
philpem@5 23435 // Compute and sort visible primitives
philpem@5 23436 CImg<uintT> visibles(primitives.size);
philpem@5 23437 CImg<floatT> zrange(primitives.size);
philpem@5 23438 unsigned int nb_visibles = 0;
philpem@5 23439 const float zmin = -focale+1.5f;
philpem@5 23440 { cimglist_for(primitives,l) {
philpem@5 23441 const CImg<tf>& primitive = primitives[l];
philpem@5 23442 switch (primitive.size()) {
philpem@5 23443
philpem@5 23444 case 1 : { // Point
philpem@5 23445 const unsigned int i0 = (unsigned int)primitive(0);
philpem@5 23446 const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
philpem@5 23447 if (z0>zmin && x0>=0 && x0<width && y0>=0 && y0<height) {
philpem@5 23448 visibles(nb_visibles) = (unsigned int)l;
philpem@5 23449 zrange(nb_visibles++) = z0;
philpem@5 23450 }
philpem@5 23451 } break;
philpem@5 23452 case 5 : { // Sphere
philpem@5 23453 const unsigned int
philpem@5 23454 i0 = (unsigned int)primitive(0),
philpem@5 23455 i1 = (unsigned int)primitive(1),
philpem@5 23456 i2 = (unsigned int)primitive(2);
philpem@5 23457 const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2));
philpem@5 23458 int radius;
philpem@5 23459 if (i2) radius = (int)(i2*focale/(z0+focale));
philpem@5 23460 else {
philpem@5 23461 const float x1 = projections(i1,0), y1 = projections(i1,1);
philpem@5 23462 const int deltax = (int)(x1-x0), deltay = (int)(y1-y0);
philpem@5 23463 radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
philpem@5 23464 }
philpem@5 23465 if (z0>zmin && x0+radius>=0 && x0-radius<width && y0+radius>=0 && y0-radius<height) {
philpem@5 23466 visibles(nb_visibles) = (unsigned int)l;
philpem@5 23467 zrange(nb_visibles++) = z0;
philpem@5 23468 }
philpem@5 23469 } break;
philpem@5 23470 case 2 : // Line
philpem@5 23471 case 6 : {
philpem@5 23472 const unsigned int
philpem@5 23473 i0 = (unsigned int)primitive(0),
philpem@5 23474 i1 = (unsigned int)primitive(1);
philpem@5 23475 const float
philpem@5 23476 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
philpem@5 23477 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2));
philpem@5 23478 float xm, xM, ym, yM;
philpem@5 23479 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
philpem@5 23480 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
philpem@5 23481 if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
philpem@5 23482 visibles(nb_visibles) = (unsigned int)l;
philpem@5 23483 zrange(nb_visibles++) = 0.5f*(z0+z1);
philpem@5 23484 }
philpem@5 23485 } break;
philpem@5 23486 case 3 : // Triangle
philpem@5 23487 case 9 : {
philpem@5 23488 const unsigned int
philpem@5 23489 i0 = (unsigned int)primitive(0),
philpem@5 23490 i1 = (unsigned int)primitive(1),
philpem@5 23491 i2 = (unsigned int)primitive(2);
philpem@5 23492 const float
philpem@5 23493 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
philpem@5 23494 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
philpem@5 23495 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2));
philpem@5 23496 float xm, xM, ym, yM;
philpem@5 23497 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
philpem@5 23498 if (x2<xm) xm = x2;
philpem@5 23499 if (x2>xM) xM = x2;
philpem@5 23500 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
philpem@5 23501 if (y2<ym) ym = y2;
philpem@5 23502 if (y2>yM) yM = y2;
philpem@5 23503 if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
philpem@5 23504 const float d = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0);
philpem@5 23505 if (double_sided || d<0) {
philpem@5 23506 visibles(nb_visibles) = (unsigned int)l;
philpem@5 23507 zrange(nb_visibles++) = (z0+z1+z2)/3;
philpem@5 23508 }
philpem@5 23509 }
philpem@5 23510 } break;
philpem@5 23511 case 4 : // Rectangle
philpem@5 23512 case 12 : {
philpem@5 23513 const unsigned int
philpem@5 23514 i0 = (unsigned int)primitive(0),
philpem@5 23515 i1 = (unsigned int)primitive(1),
philpem@5 23516 i2 = (unsigned int)primitive(2),
philpem@5 23517 i3 = (unsigned int)primitive(3);
philpem@5 23518 const float
philpem@5 23519 x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)),
philpem@5 23520 x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)),
philpem@5 23521 x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)),
philpem@5 23522 x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2));
philpem@5 23523 float xm, xM, ym, yM;
philpem@5 23524 if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; }
philpem@5 23525 if (x2<xm) xm = x2;
philpem@5 23526 if (x2>xM) xM = x2;
philpem@5 23527 if (x3<xm) xm = x3;
philpem@5 23528 if (x3>xM) xM = x3;
philpem@5 23529 if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; }
philpem@5 23530 if (y2<ym) ym = y2;
philpem@5 23531 if (y2>yM) yM = y2;
philpem@5 23532 if (y3<ym) ym = y3;
philpem@5 23533 if (y3>yM) yM = y3;
philpem@5 23534 if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) {
philpem@5 23535 const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0);
philpem@5 23536 if (double_sided || d<0) {
philpem@5 23537 visibles(nb_visibles) = (unsigned int)l;
philpem@5 23538 zrange(nb_visibles++) = (z0 + z1 + z2 + z3)/4;
philpem@5 23539 }
philpem@5 23540 }
philpem@5 23541 } break;
philpem@5 23542 default :
philpem@5 23543 throw CImgArgumentException("CImg<%s>::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,5,6,9 or 12)",
philpem@5 23544 pixel_type(),l,primitive.size());
philpem@5 23545 }}
philpem@5 23546 }
philpem@5 23547 if (nb_visibles<=0) return *this;
philpem@5 23548 CImg<uintT> permutations;
philpem@5 23549 CImg<floatT>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false);
philpem@5 23550
philpem@5 23551 // Compute light properties
philpem@5 23552 CImg<floatT> lightprops;
philpem@5 23553 switch (render_type) {
philpem@5 23554 case 3 : { // Flat Shading
philpem@5 23555 lightprops.assign(nb_visibles);
philpem@5 23556 cimg_forX(lightprops,l) {
philpem@5 23557 const CImg<tf>& primitive = primitives(visibles(permutations(l)));
philpem@5 23558 const unsigned int psize = primitive.size();
philpem@5 23559 if (psize==3 || psize==4 || psize==9 || psize==12) {
philpem@5 23560 const unsigned int
philpem@5 23561 i0 = (unsigned int)primitive(0),
philpem@5 23562 i1 = (unsigned int)primitive(1),
philpem@5 23563 i2 = (unsigned int)primitive(2);
philpem@5 23564 const float
philpem@5 23565 x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
philpem@5 23566 x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
philpem@5 23567 x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
philpem@5 23568 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
philpem@5 23569 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
philpem@5 23570 nx = dy1*dz2 - dz1*dy2,
philpem@5 23571 ny = dz1*dx2 - dx1*dz2,
philpem@5 23572 nz = dx1*dy2 - dy1*dx2,
philpem@5 23573 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
philpem@5 23574 lx = X + (x0 + x1 + x2)/3 - lightx,
philpem@5 23575 ly = Y + (y0 + y1 + y2)/3 - lighty,
philpem@5 23576 lz = Z + (z0 + z1 + z2)/3 - lightz,
philpem@5 23577 nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
philpem@5 23578 factor = cimg::max(cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
philpem@5 23579 lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
philpem@5 23580 } else lightprops[l] = 1;
philpem@5 23581 }
philpem@5 23582 } break;
philpem@5 23583
philpem@5 23584 case 4 : // Gouraud Shading
philpem@5 23585 case 5 : { // Phong-Shading
philpem@5 23586 CImg<floatT> points_normals(nb_points,3,1,1,0);
philpem@5 23587 for (unsigned int l=0; l<nb_visibles; ++l) {
philpem@5 23588 const CImg<tf>& primitive = primitives[visibles(l)];
philpem@5 23589 const unsigned int psize = primitive.size();
philpem@5 23590 const bool
philpem@5 23591 triangle_flag = (psize==3) || (psize==9),
philpem@5 23592 rectangle_flag = (psize==4) || (psize==12);
philpem@5 23593 if (triangle_flag || rectangle_flag) {
philpem@5 23594 const unsigned int
philpem@5 23595 i0 = (unsigned int)primitive(0),
philpem@5 23596 i1 = (unsigned int)primitive(1),
philpem@5 23597 i2 = (unsigned int)primitive(2),
philpem@5 23598 i3 = rectangle_flag?(unsigned int)primitive(3):0;
philpem@5 23599 const float
philpem@5 23600 x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2),
philpem@5 23601 x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2),
philpem@5 23602 x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2),
philpem@5 23603 dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0,
philpem@5 23604 dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0,
philpem@5 23605 nnx = dy1*dz2 - dz1*dy2,
philpem@5 23606 nny = dz1*dx2 - dx1*dz2,
philpem@5 23607 nnz = dx1*dy2 - dy1*dx2,
philpem@5 23608 norm = 1e-5f + (float)cimg_std::sqrt(nnx*nnx + nny*nny + nnz*nnz),
philpem@5 23609 nx = nnx/norm,
philpem@5 23610 ny = nny/norm,
philpem@5 23611 nz = nnz/norm;
philpem@5 23612 points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz;
philpem@5 23613 points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz;
philpem@5 23614 points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz;
philpem@5 23615 if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; }
philpem@5 23616 }
philpem@5 23617 }
philpem@5 23618
philpem@5 23619 if (double_sided) cimg_forX(points_normals,p) if (points_normals(p,2)>0) {
philpem@5 23620 points_normals(p,0) = -points_normals(p,0);
philpem@5 23621 points_normals(p,1) = -points_normals(p,1);
philpem@5 23622 points_normals(p,2) = -points_normals(p,2);
philpem@5 23623 }
philpem@5 23624
philpem@5 23625 if (render_type==4) {
philpem@5 23626 lightprops.assign(nb_points);
philpem@5 23627 cimg_forX(lightprops,ll) {
philpem@5 23628 const float
philpem@5 23629 nx = points_normals(ll,0),
philpem@5 23630 ny = points_normals(ll,1),
philpem@5 23631 nz = points_normals(ll,2),
philpem@5 23632 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
philpem@5 23633 lx = (float)(X + points(ll,0) - lightx),
philpem@5 23634 ly = (float)(Y + points(ll,1) - lighty),
philpem@5 23635 lz = (float)(Z + points(ll,2) - lightz),
philpem@5 23636 nl = (float)cimg_std::sqrt(1e-5f + lx*lx + ly*ly + lz*lz),
philpem@5 23637 factor = cimg::max((-lx*nx-ly*ny-lz*nz)/(norm*nl),0);
philpem@5 23638 lightprops[ll] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3);
philpem@5 23639 }
philpem@5 23640 } else {
philpem@5 23641 const unsigned int
philpem@5 23642 lw2 = light_texture.width/2 - 1,
philpem@5 23643 lh2 = light_texture.height/2 - 1;
philpem@5 23644 lightprops.assign(nb_points,2);
philpem@5 23645 cimg_forX(lightprops,ll) {
philpem@5 23646 const float
philpem@5 23647 nx = points_normals(ll,0),
philpem@5 23648 ny = points_normals(ll,1),
philpem@5 23649 nz = points_normals(ll,2),
philpem@5 23650 norm = (float)cimg_std::sqrt(1e-5f + nx*nx + ny*ny + nz*nz),
philpem@5 23651 nnx = nx/norm,
philpem@5 23652 nny = ny/norm;
philpem@5 23653 lightprops(ll,0) = lw2*(1 + nnx);
philpem@5 23654 lightprops(ll,1) = lh2*(1 + nny);
philpem@5 23655 }
philpem@5 23656 }
philpem@5 23657 } break;
philpem@5 23658 }
philpem@5 23659
philpem@5 23660 // Draw visible primitives
philpem@5 23661 const CImg<tc> default_color(1,dim,1,1,(tc)200);
philpem@5 23662 { for (unsigned int l = 0; l<nb_visibles; ++l) {
philpem@5 23663 const unsigned int n_primitive = visibles(permutations(l));
philpem@5 23664 const CImg<tf>& primitive = primitives[n_primitive];
philpem@5 23665 const CImg<tc>& color = n_primitive<colors.size?colors[n_primitive]:default_color;
philpem@5 23666 const float opac = n_primitive<nb_opacities?opacities(n_primitive,0):1.0f;
philpem@5 23667 #ifdef cimg_use_board
philpem@5 23668 BoardLib::Board &board = *(BoardLib::Board*)pboard;
philpem@5 23669 #endif
philpem@5 23670
philpem@5 23671 switch (primitive.size()) {
philpem@5 23672 case 1 : { // Colored point or sprite
philpem@5 23673 const unsigned int n0 = (unsigned int)primitive[0];
philpem@5 23674 const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
philpem@5 23675 if (color.size()==dim) {
philpem@5 23676 draw_point(x0,y0,color,opac);
philpem@5 23677 #ifdef cimg_use_board
philpem@5 23678 if (pboard) {
philpem@5 23679 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23680 board.fillCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23681 }
philpem@5 23682 #endif
philpem@5 23683 } else {
philpem@5 23684 const float z = Z + points(n0,2);
philpem@5 23685 const int
philpem@5 23686 factor = (int)(focale*100/(z+focale)),
philpem@5 23687 sw = color.width*factor/200,
philpem@5 23688 sh = color.height*factor/200;
philpem@5 23689 if (x0+sw>=0 && x0-sw<dimx() && y0+sh>=0 && y0-sh<dimy()) {
philpem@5 23690 const CImg<T> sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3);
philpem@5 23691 _draw_object3d_sprite(x0-sw,y0-sh,color,opacities[n_primitive%nb_opacities],sprite);
philpem@5 23692 #ifdef cimg_use_board
philpem@5 23693 if (pboard) {
philpem@5 23694 board.setPenColorRGBi(128,128,128);
philpem@5 23695 board.setFillColor(BoardLib::Color::none);
philpem@5 23696 board.drawRectangle((float)x0-sw,dimy()-(float)y0+sh,sw,sh);
philpem@5 23697 }
philpem@5 23698 #endif
philpem@5 23699 }
philpem@5 23700 }
philpem@5 23701 } break;
philpem@5 23702 case 2 : { // Colored line
philpem@5 23703 const unsigned int
philpem@5 23704 n0 = (unsigned int)primitive[0],
philpem@5 23705 n1 = (unsigned int)primitive[1];
philpem@5 23706 const int
philpem@5 23707 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 23708 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
philpem@5 23709 const float
philpem@5 23710 z0 = points(n0,2) + Z + focale,
philpem@5 23711 z1 = points(n1,2) + Z + focale;
philpem@5 23712 if (render_type) {
philpem@5 23713 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac);
philpem@5 23714 else draw_line(x0,y0,x1,y1,color,opac);
philpem@5 23715 #ifdef cimg_use_board
philpem@5 23716 if (pboard) {
philpem@5 23717 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23718 board.drawLine((float)x0,dimy()-(float)y0,x1,dimy()-(float)y1);
philpem@5 23719 }
philpem@5 23720 #endif
philpem@5 23721 } else {
philpem@5 23722 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac);
philpem@5 23723 #ifdef cimg_use_board
philpem@5 23724 if (pboard) {
philpem@5 23725 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23726 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23727 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 23728 }
philpem@5 23729 #endif
philpem@5 23730 }
philpem@5 23731 } break;
philpem@5 23732 case 5 : { // Colored sphere
philpem@5 23733 const unsigned int
philpem@5 23734 n0 = (unsigned int)primitive[0],
philpem@5 23735 n1 = (unsigned int)primitive[1],
philpem@5 23736 n2 = (unsigned int)primitive[2];
philpem@5 23737 const int
philpem@5 23738 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1);
philpem@5 23739 int radius;
philpem@5 23740 if (n2) radius = (int)(n2*focale/(Z+points(n0,2)+focale));
philpem@5 23741 else {
philpem@5 23742 const int
philpem@5 23743 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
philpem@5 23744 deltax = x1-x0, deltay = y1-y0;
philpem@5 23745 radius = (int)cimg_std::sqrt((float)(deltax*deltax + deltay*deltay));
philpem@5 23746 }
philpem@5 23747 switch (render_type) {
philpem@5 23748 case 0 :
philpem@5 23749 draw_point(x0,y0,color,opac);
philpem@5 23750 #ifdef cimg_use_board
philpem@5 23751 if (pboard) {
philpem@5 23752 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23753 board.fillCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23754 }
philpem@5 23755 #endif
philpem@5 23756 break;
philpem@5 23757 case 1 :
philpem@5 23758 draw_circle(x0,y0,radius,color,opac,~0U);
philpem@5 23759 #ifdef cimg_use_board
philpem@5 23760 if (pboard) {
philpem@5 23761 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23762 board.setFillColor(BoardLib::Color::none);
philpem@5 23763 board.drawCircle((float)x0,dimy()-(float)y0,(float)radius);
philpem@5 23764 }
philpem@5 23765 #endif
philpem@5 23766 break;
philpem@5 23767 default :
philpem@5 23768 draw_circle(x0,y0,radius,color,opac);
philpem@5 23769 #ifdef cimg_use_board
philpem@5 23770 if (pboard) {
philpem@5 23771 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23772 board.fillCircle((float)x0,dimy()-(float)y0,(float)radius);
philpem@5 23773 }
philpem@5 23774 #endif
philpem@5 23775 break;
philpem@5 23776 }
philpem@5 23777 } break;
philpem@5 23778 case 6 : { // Textured line
philpem@5 23779 const unsigned int
philpem@5 23780 n0 = (unsigned int)primitive[0],
philpem@5 23781 n1 = (unsigned int)primitive[1],
philpem@5 23782 tx0 = (unsigned int)primitive[2],
philpem@5 23783 ty0 = (unsigned int)primitive[3],
philpem@5 23784 tx1 = (unsigned int)primitive[4],
philpem@5 23785 ty1 = (unsigned int)primitive[5];
philpem@5 23786 const int
philpem@5 23787 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 23788 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1);
philpem@5 23789 const float
philpem@5 23790 z0 = points(n0,2) + Z + focale,
philpem@5 23791 z1 = points(n1,2) + Z + focale;
philpem@5 23792 if (render_type) {
philpem@5 23793 if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac);
philpem@5 23794 else draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac);
philpem@5 23795 #ifdef cimg_use_board
philpem@5 23796 if (pboard) {
philpem@5 23797 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 23798 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
philpem@5 23799 }
philpem@5 23800 #endif
philpem@5 23801 } else {
philpem@5 23802 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
philpem@5 23803 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac);
philpem@5 23804 #ifdef cimg_use_board
philpem@5 23805 if (pboard) {
philpem@5 23806 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 23807 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23808 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 23809 }
philpem@5 23810 #endif
philpem@5 23811 }
philpem@5 23812 } break;
philpem@5 23813 case 3 : { // Colored triangle
philpem@5 23814 const unsigned int
philpem@5 23815 n0 = (unsigned int)primitive[0],
philpem@5 23816 n1 = (unsigned int)primitive[1],
philpem@5 23817 n2 = (unsigned int)primitive[2];
philpem@5 23818 const int
philpem@5 23819 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 23820 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
philpem@5 23821 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
philpem@5 23822 const float
philpem@5 23823 z0 = points(n0,2) + Z + focale,
philpem@5 23824 z1 = points(n1,2) + Z + focale,
philpem@5 23825 z2 = points(n2,2) + Z + focale;
philpem@5 23826 switch (render_type) {
philpem@5 23827 case 0 :
philpem@5 23828 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).draw_point(x2,y2,color,opac);
philpem@5 23829 #ifdef cimg_use_board
philpem@5 23830 if (pboard) {
philpem@5 23831 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23832 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23833 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 23834 board.drawCircle((float)x2,dimy()-(float)y2,0);
philpem@5 23835 }
philpem@5 23836 #endif
philpem@5 23837 break;
philpem@5 23838 case 1 :
philpem@5 23839 if (zbuffer)
philpem@5 23840 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,opac).
philpem@5 23841 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac);
philpem@5 23842 else
philpem@5 23843 draw_line(x0,y0,x1,y1,color,opac).draw_line(x0,y0,x2,y2,color,opac).
philpem@5 23844 draw_line(x1,y1,x2,y2,color,opac);
philpem@5 23845 #ifdef cimg_use_board
philpem@5 23846 if (pboard) {
philpem@5 23847 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23848 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
philpem@5 23849 board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
philpem@5 23850 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23851 }
philpem@5 23852 #endif
philpem@5 23853 break;
philpem@5 23854 case 2 :
philpem@5 23855 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac);
philpem@5 23856 else draw_triangle(x0,y0,x1,y1,x2,y2,color,opac);
philpem@5 23857 #ifdef cimg_use_board
philpem@5 23858 if (pboard) {
philpem@5 23859 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23860 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23861 }
philpem@5 23862 #endif
philpem@5 23863 break;
philpem@5 23864 case 3 :
philpem@5 23865 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l));
philpem@5 23866 else _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l));
philpem@5 23867 #ifdef cimg_use_board
philpem@5 23868 if (pboard) {
philpem@5 23869 const float lp = cimg::min(lightprops(l),1);
philpem@5 23870 board.setPenColorRGBi((unsigned char)(color[0]*lp),
philpem@5 23871 (unsigned char)(color[1]*lp),
philpem@5 23872 (unsigned char)(color[2]*lp),
philpem@5 23873 (unsigned char)(opac*255));
philpem@5 23874 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23875 }
philpem@5 23876 #endif
philpem@5 23877 break;
philpem@5 23878 case 4 :
philpem@5 23879 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
philpem@5 23880 else draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprops(n0),lightprops(n1),lightprops(n2),opac);
philpem@5 23881 #ifdef cimg_use_board
philpem@5 23882 if (pboard) {
philpem@5 23883 board.setPenColorRGBi((unsigned char)(color[0]),
philpem@5 23884 (unsigned char)(color[1]),
philpem@5 23885 (unsigned char)(color[2]),
philpem@5 23886 (unsigned char)(opac*255));
philpem@5 23887 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
philpem@5 23888 (float)x1,dimy()-(float)y1,lightprops(n1),
philpem@5 23889 (float)x2,dimy()-(float)y2,lightprops(n2));
philpem@5 23890 }
philpem@5 23891 #endif
philpem@5 23892 break;
philpem@5 23893 case 5 : {
philpem@5 23894 const unsigned int
philpem@5 23895 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
philpem@5 23896 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
philpem@5 23897 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1);
philpem@5 23898 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
philpem@5 23899 else draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac);
philpem@5 23900 #ifdef cimg_use_board
philpem@5 23901 if (pboard) {
philpem@5 23902 const float
philpem@5 23903 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
philpem@5 23904 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
philpem@5 23905 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
philpem@5 23906 board.setPenColorRGBi((unsigned char)(color[0]),
philpem@5 23907 (unsigned char)(color[1]),
philpem@5 23908 (unsigned char)(color[2]),
philpem@5 23909 (unsigned char)(opac*255));
philpem@5 23910 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
philpem@5 23911 (float)x1,dimy()-(float)y1,l1,
philpem@5 23912 (float)x2,dimy()-(float)y2,l2);
philpem@5 23913 }
philpem@5 23914 #endif
philpem@5 23915 } break;
philpem@5 23916 }
philpem@5 23917 } break;
philpem@5 23918 case 4 : { // Colored rectangle
philpem@5 23919 const unsigned int
philpem@5 23920 n0 = (unsigned int)primitive[0],
philpem@5 23921 n1 = (unsigned int)primitive[1],
philpem@5 23922 n2 = (unsigned int)primitive[2],
philpem@5 23923 n3 = (unsigned int)primitive[3];
philpem@5 23924 const int
philpem@5 23925 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 23926 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
philpem@5 23927 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
philpem@5 23928 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
philpem@5 23929 const float
philpem@5 23930 z0 = points(n0,2) + Z + focale,
philpem@5 23931 z1 = points(n1,2) + Z + focale,
philpem@5 23932 z2 = points(n2,2) + Z + focale,
philpem@5 23933 z3 = points(n3,2) + Z + focale;
philpem@5 23934 switch (render_type) {
philpem@5 23935 case 0 :
philpem@5 23936 draw_point(x0,y0,color,opac).draw_point(x1,y1,color,opac).
philpem@5 23937 draw_point(x2,y2,color,opac).draw_point(x3,y3,color,opac);
philpem@5 23938 #ifdef cimg_use_board
philpem@5 23939 if (pboard) {
philpem@5 23940 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23941 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 23942 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 23943 board.drawCircle((float)x2,dimy()-(float)y2,0);
philpem@5 23944 board.drawCircle((float)x3,dimy()-(float)y3,0);
philpem@5 23945 }
philpem@5 23946 #endif
philpem@5 23947 break;
philpem@5 23948 case 1 :
philpem@5 23949 if (zbuffer)
philpem@5 23950 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,opac).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,opac).
philpem@5 23951 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,opac).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,opac);
philpem@5 23952 else
philpem@5 23953 draw_line(x0,y0,x1,y1,color,opac).draw_line(x1,y1,x2,y2,color,opac).
philpem@5 23954 draw_line(x2,y2,x3,y3,color,opac).draw_line(x3,y3,x0,y0,color,opac);
philpem@5 23955 #ifdef cimg_use_board
philpem@5 23956 if (pboard) {
philpem@5 23957 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23958 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
philpem@5 23959 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23960 board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 23961 board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
philpem@5 23962 }
philpem@5 23963 #endif
philpem@5 23964 break;
philpem@5 23965 case 2 :
philpem@5 23966 if (zbuffer)
philpem@5 23967 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,opac).draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,opac);
philpem@5 23968 else
philpem@5 23969 draw_triangle(x0,y0,x1,y1,x2,y2,color,opac).draw_triangle(x0,y0,x2,y2,x3,y3,color,opac);
philpem@5 23970 #ifdef cimg_use_board
philpem@5 23971 if (pboard) {
philpem@5 23972 board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opac*255));
philpem@5 23973 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23974 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 23975 }
philpem@5 23976 #endif
philpem@5 23977 break;
philpem@5 23978 case 3 :
philpem@5 23979 if (zbuffer)
philpem@5 23980 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color.data,opac,lightprops(l)).
philpem@5 23981 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color.data,opac,lightprops(l));
philpem@5 23982 else
philpem@5 23983 _draw_triangle(x0,y0,x1,y1,x2,y2,color.data,opac,lightprops(l)).
philpem@5 23984 _draw_triangle(x0,y0,x2,y2,x3,y3,color.data,opac,lightprops(l));
philpem@5 23985 #ifdef cimg_use_board
philpem@5 23986 if (pboard) {
philpem@5 23987 const float lp = cimg::min(lightprops(l),1);
philpem@5 23988 board.setPenColorRGBi((unsigned char)(color[0]*lp),
philpem@5 23989 (unsigned char)(color[1]*lp),
philpem@5 23990 (unsigned char)(color[2]*lp),(unsigned char)(opac*255));
philpem@5 23991 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 23992 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 23993 }
philpem@5 23994 #endif
philpem@5 23995 break;
philpem@5 23996 case 4 : {
philpem@5 23997 const float
philpem@5 23998 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
philpem@5 23999 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
philpem@5 24000 if (zbuffer)
philpem@5 24001 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,lightprop0,lightprop1,lightprop2,opac).
philpem@5 24002 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,lightprop0,lightprop2,lightprop3,opac);
philpem@5 24003 else
philpem@5 24004 draw_triangle(x0,y0,x1,y1,x2,y2,color,lightprop0,lightprop1,lightprop2,opac).
philpem@5 24005 draw_triangle(x0,y0,x2,y2,x3,y3,color,lightprop0,lightprop2,lightprop3,opac);
philpem@5 24006 #ifdef cimg_use_board
philpem@5 24007 if (pboard) {
philpem@5 24008 board.setPenColorRGBi((unsigned char)(color[0]),
philpem@5 24009 (unsigned char)(color[1]),
philpem@5 24010 (unsigned char)(color[2]),
philpem@5 24011 (unsigned char)(opac*255));
philpem@5 24012 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
philpem@5 24013 (float)x1,dimy()-(float)y1,lightprop1,
philpem@5 24014 (float)x2,dimy()-(float)y2,lightprop2);
philpem@5 24015 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
philpem@5 24016 (float)x2,dimy()-(float)y2,lightprop2,
philpem@5 24017 (float)x3,dimy()-(float)y3,lightprop3);
philpem@5 24018 }
philpem@5 24019 #endif
philpem@5 24020 } break;
philpem@5 24021 case 5 : {
philpem@5 24022 const unsigned int
philpem@5 24023 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
philpem@5 24024 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
philpem@5 24025 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
philpem@5 24026 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
philpem@5 24027 if (zbuffer)
philpem@5 24028 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
philpem@5 24029 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
philpem@5 24030 else
philpem@5 24031 draw_triangle(x0,y0,x1,y1,x2,y2,color,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
philpem@5 24032 draw_triangle(x0,y0,x2,y2,x3,y3,color,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
philpem@5 24033 #ifdef cimg_use_board
philpem@5 24034 if (pboard) {
philpem@5 24035 const float
philpem@5 24036 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
philpem@5 24037 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
philpem@5 24038 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
philpem@5 24039 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
philpem@5 24040 board.setPenColorRGBi((unsigned char)(color[0]),
philpem@5 24041 (unsigned char)(color[1]),
philpem@5 24042 (unsigned char)(color[2]),
philpem@5 24043 (unsigned char)(opac*255));
philpem@5 24044 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
philpem@5 24045 (float)x1,dimy()-(float)y1,l1,
philpem@5 24046 (float)x2,dimy()-(float)y2,l2);
philpem@5 24047 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
philpem@5 24048 (float)x2,dimy()-(float)y2,l2,
philpem@5 24049 (float)x3,dimy()-(float)y3,l3);
philpem@5 24050 }
philpem@5 24051 #endif
philpem@5 24052 } break;
philpem@5 24053 }
philpem@5 24054 } break;
philpem@5 24055 case 9 : { // Textured triangle
philpem@5 24056 const unsigned int
philpem@5 24057 n0 = (unsigned int)primitive[0],
philpem@5 24058 n1 = (unsigned int)primitive[1],
philpem@5 24059 n2 = (unsigned int)primitive[2],
philpem@5 24060 tx0 = (unsigned int)primitive[3],
philpem@5 24061 ty0 = (unsigned int)primitive[4],
philpem@5 24062 tx1 = (unsigned int)primitive[5],
philpem@5 24063 ty1 = (unsigned int)primitive[6],
philpem@5 24064 tx2 = (unsigned int)primitive[7],
philpem@5 24065 ty2 = (unsigned int)primitive[8];
philpem@5 24066 const int
philpem@5 24067 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 24068 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
philpem@5 24069 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1);
philpem@5 24070 const float
philpem@5 24071 z0 = points(n0,2) + Z + focale,
philpem@5 24072 z1 = points(n1,2) + Z + focale,
philpem@5 24073 z2 = points(n2,2) + Z + focale;
philpem@5 24074 switch (render_type) {
philpem@5 24075 case 0 :
philpem@5 24076 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
philpem@5 24077 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
philpem@5 24078 draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac);
philpem@5 24079 #ifdef cimg_use_board
philpem@5 24080 if (pboard) {
philpem@5 24081 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24082 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 24083 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 24084 board.drawCircle((float)x2,dimy()-(float)y2,0);
philpem@5 24085 }
philpem@5 24086 #endif
philpem@5 24087 break;
philpem@5 24088 case 1 :
philpem@5 24089 if (zbuffer)
philpem@5 24090 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
philpem@5 24091 draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
philpem@5 24092 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
philpem@5 24093 else
philpem@5 24094 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
philpem@5 24095 draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opac).
philpem@5 24096 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac);
philpem@5 24097 #ifdef cimg_use_board
philpem@5 24098 if (pboard) {
philpem@5 24099 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24100 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
philpem@5 24101 board.drawLine((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2);
philpem@5 24102 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24103 }
philpem@5 24104 #endif
philpem@5 24105 break;
philpem@5 24106 case 2 :
philpem@5 24107 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
philpem@5 24108 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac);
philpem@5 24109 #ifdef cimg_use_board
philpem@5 24110 if (pboard) {
philpem@5 24111 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24112 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24113 }
philpem@5 24114 #endif
philpem@5 24115 break;
philpem@5 24116 case 3 :
philpem@5 24117 if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
philpem@5 24118 else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l));
philpem@5 24119 #ifdef cimg_use_board
philpem@5 24120 if (pboard) {
philpem@5 24121 const float lp = cimg::min(lightprops(l),1);
philpem@5 24122 board.setPenColorRGBi((unsigned char)(128*lp),
philpem@5 24123 (unsigned char)(128*lp),
philpem@5 24124 (unsigned char)(128*lp),
philpem@5 24125 (unsigned char)(opac*255));
philpem@5 24126 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24127 }
philpem@5 24128 #endif
philpem@5 24129 break;
philpem@5 24130 case 4 :
philpem@5 24131 if (zbuffer)
philpem@5 24132 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
philpem@5 24133 else
philpem@5 24134 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac);
philpem@5 24135 #ifdef cimg_use_board
philpem@5 24136 if (pboard) {
philpem@5 24137 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24138 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprops(n0),
philpem@5 24139 (float)x1,dimy()-(float)y1,lightprops(n1),
philpem@5 24140 (float)x2,dimy()-(float)y2,lightprops(n2));
philpem@5 24141 }
philpem@5 24142 #endif
philpem@5 24143 break;
philpem@5 24144 case 5 :
philpem@5 24145 if (zbuffer)
philpem@5 24146 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
philpem@5 24147 (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
philpem@5 24148 (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
philpem@5 24149 (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
philpem@5 24150 opac);
philpem@5 24151 else
philpem@5 24152 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,
philpem@5 24153 (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1),
philpem@5 24154 (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1),
philpem@5 24155 (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1),
philpem@5 24156 opac);
philpem@5 24157 #ifdef cimg_use_board
philpem@5 24158 if (pboard) {
philpem@5 24159 const float
philpem@5 24160 l0 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n0,0))), (int)(light_texture.dimy()/2*(1+lightprops(n0,1)))),
philpem@5 24161 l1 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n1,0))), (int)(light_texture.dimy()/2*(1+lightprops(n1,1)))),
philpem@5 24162 l2 = light_texture((int)(light_texture.dimx()/2*(1+lightprops(n2,0))), (int)(light_texture.dimy()/2*(1+lightprops(n2,1))));
philpem@5 24163 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24164 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,(float)x1,dimy()-(float)y1,l1,(float)x2,dimy()-(float)y2,l2);
philpem@5 24165 }
philpem@5 24166 #endif
philpem@5 24167 break;
philpem@5 24168 }
philpem@5 24169 } break;
philpem@5 24170 case 12 : { // Textured rectangle
philpem@5 24171 const unsigned int
philpem@5 24172 n0 = (unsigned int)primitive[0],
philpem@5 24173 n1 = (unsigned int)primitive[1],
philpem@5 24174 n2 = (unsigned int)primitive[2],
philpem@5 24175 n3 = (unsigned int)primitive[3],
philpem@5 24176 tx0 = (unsigned int)primitive[4],
philpem@5 24177 ty0 = (unsigned int)primitive[5],
philpem@5 24178 tx1 = (unsigned int)primitive[6],
philpem@5 24179 ty1 = (unsigned int)primitive[7],
philpem@5 24180 tx2 = (unsigned int)primitive[8],
philpem@5 24181 ty2 = (unsigned int)primitive[9],
philpem@5 24182 tx3 = (unsigned int)primitive[10],
philpem@5 24183 ty3 = (unsigned int)primitive[11];
philpem@5 24184 const int
philpem@5 24185 x0 = (int)projections(n0,0), y0 = (int)projections(n0,1),
philpem@5 24186 x1 = (int)projections(n1,0), y1 = (int)projections(n1,1),
philpem@5 24187 x2 = (int)projections(n2,0), y2 = (int)projections(n2,1),
philpem@5 24188 x3 = (int)projections(n3,0), y3 = (int)projections(n3,1);
philpem@5 24189 const float
philpem@5 24190 z0 = points(n0,2) + Z + focale,
philpem@5 24191 z1 = points(n1,2) + Z + focale,
philpem@5 24192 z2 = points(n2,2) + Z + focale,
philpem@5 24193 z3 = points(n3,2) + Z + focale;
philpem@5 24194 switch (render_type) {
philpem@5 24195 case 0 :
philpem@5 24196 draw_point(x0,y0,color.get_vector_at(tx0,ty0),opac).
philpem@5 24197 draw_point(x1,y1,color.get_vector_at(tx1,ty1),opac).
philpem@5 24198 draw_point(x2,y2,color.get_vector_at(tx2,ty2),opac).
philpem@5 24199 draw_point(x3,y3,color.get_vector_at(tx3,ty3),opac);
philpem@5 24200 #ifdef cimg_use_board
philpem@5 24201 if (pboard) {
philpem@5 24202 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24203 board.drawCircle((float)x0,dimy()-(float)y0,0);
philpem@5 24204 board.drawCircle((float)x1,dimy()-(float)y1,0);
philpem@5 24205 board.drawCircle((float)x2,dimy()-(float)y2,0);
philpem@5 24206 board.drawCircle((float)x3,dimy()-(float)y3,0);
philpem@5 24207 }
philpem@5 24208 #endif
philpem@5 24209 break;
philpem@5 24210 case 1 :
philpem@5 24211 if (zbuffer)
philpem@5 24212 draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
philpem@5 24213 draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
philpem@5 24214 draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
philpem@5 24215 draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
philpem@5 24216 else
philpem@5 24217 draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opac).
philpem@5 24218 draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opac).
philpem@5 24219 draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opac).
philpem@5 24220 draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opac);
philpem@5 24221 #ifdef cimg_use_board
philpem@5 24222 if (pboard) {
philpem@5 24223 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24224 board.drawLine((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1);
philpem@5 24225 board.drawLine((float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24226 board.drawLine((float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 24227 board.drawLine((float)x3,dimy()-(float)y3,(float)x0,dimy()-(float)y0);
philpem@5 24228 }
philpem@5 24229 #endif
philpem@5 24230 break;
philpem@5 24231 case 2 :
philpem@5 24232 if (zbuffer)
philpem@5 24233 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
philpem@5 24234 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
philpem@5 24235 else
philpem@5 24236 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac).
philpem@5 24237 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac);
philpem@5 24238 #ifdef cimg_use_board
philpem@5 24239 if (pboard) {
philpem@5 24240 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24241 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24242 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 24243 }
philpem@5 24244 #endif
philpem@5 24245 break;
philpem@5 24246 case 3 :
philpem@5 24247 if (zbuffer)
philpem@5 24248 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
philpem@5 24249 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
philpem@5 24250 else
philpem@5 24251 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)).
philpem@5 24252 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l));
philpem@5 24253 #ifdef cimg_use_board
philpem@5 24254 if (pboard) {
philpem@5 24255 const float lp = cimg::min(lightprops(l),1);
philpem@5 24256 board.setPenColorRGBi((unsigned char)(128*lp),
philpem@5 24257 (unsigned char)(128*lp),
philpem@5 24258 (unsigned char)(128*lp),
philpem@5 24259 (unsigned char)(opac*255));
philpem@5 24260 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x1,dimy()-(float)y1,(float)x2,dimy()-(float)y2);
philpem@5 24261 board.fillTriangle((float)x0,dimy()-(float)y0,(float)x2,dimy()-(float)y2,(float)x3,dimy()-(float)y3);
philpem@5 24262 }
philpem@5 24263 #endif
philpem@5 24264 break;
philpem@5 24265 case 4 : {
philpem@5 24266 const float
philpem@5 24267 lightprop0 = lightprops(n0), lightprop1 = lightprops(n1),
philpem@5 24268 lightprop2 = lightprops(n2), lightprop3 = lightprops(n3);
philpem@5 24269 if (zbuffer)
philpem@5 24270 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
philpem@5 24271 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
philpem@5 24272 else
philpem@5 24273 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac).
philpem@5 24274 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac);
philpem@5 24275 #ifdef cimg_use_board
philpem@5 24276 if (pboard) {
philpem@5 24277 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24278 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
philpem@5 24279 (float)x1,dimy()-(float)y1,lightprop1,
philpem@5 24280 (float)x2,dimy()-(float)y2,lightprop2);
philpem@5 24281 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,lightprop0,
philpem@5 24282 (float)x2,dimy()-(float)y2,lightprop2,
philpem@5 24283 (float)x3,dimy()-(float)y3,lightprop3);
philpem@5 24284 }
philpem@5 24285 #endif
philpem@5 24286 } break;
philpem@5 24287 case 5 : {
philpem@5 24288 const unsigned int
philpem@5 24289 lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1),
philpem@5 24290 lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1),
philpem@5 24291 lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1),
philpem@5 24292 lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1);
philpem@5 24293 if (zbuffer)
philpem@5 24294 draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
philpem@5 24295 draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
philpem@5 24296 else
philpem@5 24297 draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac).
philpem@5 24298 draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac);
philpem@5 24299 #ifdef cimg_use_board
philpem@5 24300 if (pboard) {
philpem@5 24301 const float
philpem@5 24302 l0 = light_texture((int)(light_texture.dimx()/2*(1+lx0)), (int)(light_texture.dimy()/2*(1+ly0))),
philpem@5 24303 l1 = light_texture((int)(light_texture.dimx()/2*(1+lx1)), (int)(light_texture.dimy()/2*(1+ly1))),
philpem@5 24304 l2 = light_texture((int)(light_texture.dimx()/2*(1+lx2)), (int)(light_texture.dimy()/2*(1+ly2))),
philpem@5 24305 l3 = light_texture((int)(light_texture.dimx()/2*(1+lx3)), (int)(light_texture.dimy()/2*(1+ly3)));
philpem@5 24306 board.setPenColorRGBi(128,128,128,(unsigned char)(opac*255));
philpem@5 24307 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
philpem@5 24308 (float)x1,dimy()-(float)y1,l1,
philpem@5 24309 (float)x2,dimy()-(float)y2,l2);
philpem@5 24310 board.fillGouraudTriangle((float)x0,dimy()-(float)y0,l0,
philpem@5 24311 (float)x2,dimy()-(float)y2,l2,
philpem@5 24312 (float)x3,dimy()-(float)y3,l3);
philpem@5 24313 }
philpem@5 24314 #endif
philpem@5 24315 } break;
philpem@5 24316 }
philpem@5 24317 } break;
philpem@5 24318 }
philpem@5 24319 }
philpem@5 24320 }
philpem@5 24321 return *this;
philpem@5 24322 }
philpem@5 24323
philpem@5 24324 //! Draw a 3D object.
philpem@5 24325 /**
philpem@5 24326 \param X = X-coordinate of the 3d object position
philpem@5 24327 \param Y = Y-coordinate of the 3d object position
philpem@5 24328 \param Z = Z-coordinate of the 3d object position
philpem@5 24329 \param points = Image N*3 describing 3D point coordinates
philpem@5 24330 \param primitives = List of P primitives
philpem@5 24331 \param colors = List of P color (or textures)
philpem@5 24332 \param opacities = Image of P opacities
philpem@5 24333 \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud)
philpem@5 24334 \param double_sided = Tell if object faces have two sides or are oriented.
philpem@5 24335 \param focale = length of the focale
philpem@5 24336 \param lightx = X-coordinate of the light
philpem@5 24337 \param lighty = Y-coordinate of the light
philpem@5 24338 \param lightz = Z-coordinate of the light
philpem@5 24339 \param specular_shine = Shininess of the object
philpem@5 24340 **/
philpem@5 24341 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24342 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
philpem@5 24343 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 24344 const CImgList<tc>& colors, const CImgList<to>& opacities,
philpem@5 24345 const unsigned int render_type=4,
philpem@5 24346 const bool double_sided=false, const float focale=500,
philpem@5 24347 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24348 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24349 float *const zbuffer=0) {
philpem@5 24350 if (!points) return *this;
philpem@5 24351 return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
philpem@5 24352 primitives,colors,opacities,opacities.size,
philpem@5 24353 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24354 }
philpem@5 24355
philpem@5 24356 #ifdef cimg_use_board
philpem@5 24357 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24358 CImg<T>& draw_object3d(BoardLib::Board& board,
philpem@5 24359 const float x0, const float y0, const float z0,
philpem@5 24360 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 24361 const CImgList<tc>& colors, const CImgList<to>& opacities,
philpem@5 24362 const unsigned int render_type=4,
philpem@5 24363 const bool double_sided=false, const float focale=500,
philpem@5 24364 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24365 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24366 float *const zbuffer=0) {
philpem@5 24367 if (!points) return *this;
philpem@5 24368 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
philpem@5 24369 primitives,colors,opacities,opacities.size,
philpem@5 24370 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24371 }
philpem@5 24372 #endif
philpem@5 24373
philpem@5 24374 //! Draw a 3D object.
philpem@5 24375 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24376 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
philpem@5 24377 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 24378 const CImgList<tc>& colors, const CImgList<to>& opacities,
philpem@5 24379 const unsigned int render_type=4,
philpem@5 24380 const bool double_sided=false, const float focale=500,
philpem@5 24381 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24382 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24383 float *const zbuffer=0) {
philpem@5 24384 if (!points) return *this;
philpem@5 24385 return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
philpem@5 24386 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24387 }
philpem@5 24388
philpem@5 24389 #ifdef cimg_use_board
philpem@5 24390 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24391 CImg<T>& draw_object3d(BoardLib::Board& board,
philpem@5 24392 const float x0, const float y0, const float z0,
philpem@5 24393 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 24394 const CImgList<tc>& colors, const CImgList<to>& opacities,
philpem@5 24395 const unsigned int render_type=4,
philpem@5 24396 const bool double_sided=false, const float focale=500,
philpem@5 24397 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24398 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24399 float *const zbuffer=0) {
philpem@5 24400 if (!points) return *this;
philpem@5 24401 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size,
philpem@5 24402 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24403 }
philpem@5 24404 #endif
philpem@5 24405
philpem@5 24406 //! Draw a 3D object.
philpem@5 24407 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24408 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
philpem@5 24409 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 24410 const CImgList<tc>& colors, const CImg<to>& opacities,
philpem@5 24411 const unsigned int render_type=4,
philpem@5 24412 const bool double_sided=false, const float focale=500,
philpem@5 24413 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24414 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24415 float *const zbuffer=0) {
philpem@5 24416 if (!points) return *this;
philpem@5 24417 return _draw_object3d(0,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width,
philpem@5 24418 primitives,colors,opacities,opacities.size(),
philpem@5 24419 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24420 }
philpem@5 24421
philpem@5 24422 #ifdef cimg_use_board
philpem@5 24423 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24424 CImg<T>& draw_object3d(BoardLib::Board& board,
philpem@5 24425 const float x0, const float y0, const float z0,
philpem@5 24426 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 24427 const CImgList<tc>& colors, const CImg<to>& opacities,
philpem@5 24428 const unsigned int render_type=4,
philpem@5 24429 const bool double_sided=false, const float focale=500,
philpem@5 24430 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24431 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24432 float *const zbuffer=0) {
philpem@5 24433 if (!points) return *this;
philpem@5 24434 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points.height<3?points:points.get_resize(-100,3,1,1,0),points.width
philpem@5 24435 ,primitives,colors,opacities,opacities.size(),
philpem@5 24436 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24437 }
philpem@5 24438 #endif
philpem@5 24439
philpem@5 24440 //! Draw a 3D object.
philpem@5 24441 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24442 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
philpem@5 24443 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 24444 const CImgList<tc>& colors, const CImg<to>& opacities,
philpem@5 24445 const unsigned int render_type=4,
philpem@5 24446 const bool double_sided=false, const float focale=500,
philpem@5 24447 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24448 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24449 float *const zbuffer=0) {
philpem@5 24450 if (!points) return *this;
philpem@5 24451 return _draw_object3d(0,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
philpem@5 24452 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24453 }
philpem@5 24454
philpem@5 24455 #ifdef cimg_use_board
philpem@5 24456 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24457 CImg<T>& draw_object3d(BoardLib::Board& board,
philpem@5 24458 const float x0, const float y0, const float z0,
philpem@5 24459 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 24460 const CImgList<tc>& colors, const CImg<to>& opacities,
philpem@5 24461 const unsigned int render_type=4,
philpem@5 24462 const bool double_sided=false, const float focale=500,
philpem@5 24463 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24464 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24465 float *const zbuffer=0) {
philpem@5 24466 if (!points) return *this;
philpem@5 24467 return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,points,points.size,primitives,colors,opacities,opacities.size(),
philpem@5 24468 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine);
philpem@5 24469 }
philpem@5 24470 #endif
philpem@5 24471
philpem@5 24472 //! Draw a 3D object.
philpem@5 24473 template<typename tp, typename tf, typename tc>
philpem@5 24474 CImg<T>& draw_object3d(const float x0, const float y0, const float z0,
philpem@5 24475 const tp& points, const CImgList<tf>& primitives,
philpem@5 24476 const CImgList<tc>& colors,
philpem@5 24477 const unsigned int render_type=4,
philpem@5 24478 const bool double_sided=false, const float focale=500,
philpem@5 24479 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24480 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24481 float *const zbuffer=0) {
philpem@5 24482 static const CImg<floatT> opacities;
philpem@5 24483 return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
philpem@5 24484 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
philpem@5 24485 }
philpem@5 24486
philpem@5 24487 #ifdef cimg_use_board
philpem@5 24488 template<typename tp, typename tf, typename tc, typename to>
philpem@5 24489 CImg<T>& draw_object3d(BoardLib::Board& board,
philpem@5 24490 const float x0, const float y0, const float z0,
philpem@5 24491 const tp& points, const CImgList<tf>& primitives,
philpem@5 24492 const CImgList<tc>& colors,
philpem@5 24493 const unsigned int render_type=4,
philpem@5 24494 const bool double_sided=false, const float focale=500,
philpem@5 24495 const float lightx=0, const float lighty=0, const float lightz=-5000,
philpem@5 24496 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 24497 float *const zbuffer=0) {
philpem@5 24498 static const CImg<floatT> opacities;
philpem@5 24499 return draw_object3d(x0,y0,z0,points,primitives,colors,opacities,
philpem@5 24500 render_type,double_sided,focale,lightx,lighty,lightz,specular_light,specular_shine,zbuffer);
philpem@5 24501 }
philpem@5 24502 #endif
philpem@5 24503
philpem@5 24504 //@}
philpem@5 24505 //----------------------------
philpem@5 24506 //
philpem@5 24507 //! \name Image Filtering
philpem@5 24508 //@{
philpem@5 24509 //----------------------------
philpem@5 24510
philpem@5 24511 //! Compute the correlation of the instance image by a mask.
philpem@5 24512 /**
philpem@5 24513 The correlation of the instance image \p *this by the mask \p mask is defined to be :
philpem@5 24514
philpem@5 24515 res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k)
philpem@5 24516
philpem@5 24517 \param mask = the correlation kernel.
philpem@5 24518 \param cond = the border condition type (0=zero, 1=dirichlet)
philpem@5 24519 \param weighted_correl = enable local normalization.
philpem@5 24520 **/
philpem@5 24521 template<typename t>
philpem@5 24522 CImg<T>& correlate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_correl=false) {
philpem@5 24523 return get_correlate(mask,cond,weighted_correl).transfer_to(*this);
philpem@5 24524 }
philpem@5 24525
philpem@5 24526 template<typename t>
philpem@5 24527 CImg<typename cimg::superset2<T,t,float>::type> get_correlate(const CImg<t>& mask, const unsigned int cond=1,
philpem@5 24528 const bool weighted_correl=false) const {
philpem@5 24529 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 24530 if (is_empty()) return *this;
philpem@5 24531 if (!mask || mask.dim!=1)
philpem@5 24532 throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
philpem@5 24533 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
philpem@5 24534 CImg<Ttfloat> dest(width,height,depth,dim);
philpem@5 24535 if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) {
philpem@5 24536 // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 mask (with cond=1)
philpem@5 24537 switch (mask.depth) {
philpem@5 24538 case 3 : {
philpem@5 24539 T I[27] = { 0 };
philpem@5 24540 cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24541 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] +
philpem@5 24542 I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
philpem@5 24543 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] +
philpem@5 24544 I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
philpem@5 24545 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
philpem@5 24546 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
philpem@5 24547 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] +
philpem@5 24548 I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
philpem@5 24549 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26]);
philpem@5 24550 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) {
philpem@5 24551 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] +
philpem@5 24552 I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
philpem@5 24553 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] +
philpem@5 24554 I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
philpem@5 24555 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
philpem@5 24556 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
philpem@5 24557 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] +
philpem@5 24558 I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
philpem@5 24559 I[24]*I[24] + I[25]*I[25] + I[26]*I[26]);
philpem@5 24560 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24561 }
philpem@5 24562 } break;
philpem@5 24563 case 2 : {
philpem@5 24564 T I[8] = { 0 };
philpem@5 24565 cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24566 (I[0]*mask[0] + I[1]*mask[1] +
philpem@5 24567 I[2]*mask[2] + I[3]*mask[3] +
philpem@5 24568 I[4]*mask[4] + I[5]*mask[5] +
philpem@5 24569 I[6]*mask[6] + I[7]*mask[7]);
philpem@5 24570 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) {
philpem@5 24571 const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
philpem@5 24572 I[2]*I[2] + I[3]*I[3] +
philpem@5 24573 I[4]*I[4] + I[5]*I[5] +
philpem@5 24574 I[6]*I[6] + I[7]*I[7]);
philpem@5 24575 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24576 }
philpem@5 24577 } break;
philpem@5 24578 default :
philpem@5 24579 case 1 :
philpem@5 24580 switch (mask.width) {
philpem@5 24581 case 6 : {
philpem@5 24582 T I[36] = { 0 };
philpem@5 24583 cimg_forZV(*this,z,v) cimg_for6x6(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24584 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] + I[ 5]*mask[ 5] +
philpem@5 24585 I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
philpem@5 24586 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] +
philpem@5 24587 I[18]*mask[18] + I[19]*mask[19] + I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] +
philpem@5 24588 I[24]*mask[24] + I[25]*mask[25] + I[26]*mask[26] + I[27]*mask[27] + I[28]*mask[28] + I[29]*mask[29] +
philpem@5 24589 I[30]*mask[30] + I[31]*mask[31] + I[32]*mask[32] + I[33]*mask[33] + I[34]*mask[34] + I[35]*mask[35]);
philpem@5 24590 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
philpem@5 24591 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] + I[ 5]*I[ 5] +
philpem@5 24592 I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
philpem@5 24593 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15] + I[16]*I[16] + I[17]*I[17] +
philpem@5 24594 I[18]*I[18] + I[19]*I[19] + I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] +
philpem@5 24595 I[24]*I[24] + I[25]*I[25] + I[26]*I[26] + I[27]*I[27] + I[28]*I[28] + I[29]*I[29] +
philpem@5 24596 I[30]*I[30] + I[31]*I[31] + I[32]*I[32] + I[33]*I[33] + I[34]*I[34] + I[35]*I[35]);
philpem@5 24597 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24598 }
philpem@5 24599 } break;
philpem@5 24600 case 5 : {
philpem@5 24601 T I[25] = { 0 };
philpem@5 24602 cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24603 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] + I[ 4]*mask[ 4] +
philpem@5 24604 I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] + I[ 8]*mask[ 8] + I[ 9]*mask[ 9] +
philpem@5 24605 I[10]*mask[10] + I[11]*mask[11] + I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] +
philpem@5 24606 I[15]*mask[15] + I[16]*mask[16] + I[17]*mask[17] + I[18]*mask[18] + I[19]*mask[19] +
philpem@5 24607 I[20]*mask[20] + I[21]*mask[21] + I[22]*mask[22] + I[23]*mask[23] + I[24]*mask[24]);
philpem@5 24608 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) {
philpem@5 24609 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] + I[ 4]*I[ 4] +
philpem@5 24610 I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] + I[ 8]*I[ 8] + I[ 9]*I[ 9] +
philpem@5 24611 I[10]*I[10] + I[11]*I[11] + I[12]*I[12] + I[13]*I[13] + I[14]*I[14] +
philpem@5 24612 I[15]*I[15] + I[16]*I[16] + I[17]*I[17] + I[18]*I[18] + I[19]*I[19] +
philpem@5 24613 I[20]*I[20] + I[21]*I[21] + I[22]*I[22] + I[23]*I[23] + I[24]*I[24]);
philpem@5 24614 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24615 }
philpem@5 24616 } break;
philpem@5 24617 case 4 : {
philpem@5 24618 T I[16] = { 0 };
philpem@5 24619 cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24620 (I[ 0]*mask[ 0] + I[ 1]*mask[ 1] + I[ 2]*mask[ 2] + I[ 3]*mask[ 3] +
philpem@5 24621 I[ 4]*mask[ 4] + I[ 5]*mask[ 5] + I[ 6]*mask[ 6] + I[ 7]*mask[ 7] +
philpem@5 24622 I[ 8]*mask[ 8] + I[ 9]*mask[ 9] + I[10]*mask[10] + I[11]*mask[11] +
philpem@5 24623 I[12]*mask[12] + I[13]*mask[13] + I[14]*mask[14] + I[15]*mask[15]);
philpem@5 24624 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) {
philpem@5 24625 const double weight = (double)(I[ 0]*I[ 0] + I[ 1]*I[ 1] + I[ 2]*I[ 2] + I[ 3]*I[ 3] +
philpem@5 24626 I[ 4]*I[ 4] + I[ 5]*I[ 5] + I[ 6]*I[ 6] + I[ 7]*I[ 7] +
philpem@5 24627 I[ 8]*I[ 8] + I[ 9]*I[ 9] + I[10]*I[10] + I[11]*I[11] +
philpem@5 24628 I[12]*I[12] + I[13]*I[13] + I[14]*I[14] + I[15]*I[15]);
philpem@5 24629 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24630 }
philpem@5 24631 } break;
philpem@5 24632 case 3 : {
philpem@5 24633 T I[9] = { 0 };
philpem@5 24634 cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24635 (I[0]*mask[0] + I[1]*mask[1] + I[2]*mask[2] +
philpem@5 24636 I[3]*mask[3] + I[4]*mask[4] + I[5]*mask[5] +
philpem@5 24637 I[6]*mask[6] + I[7]*mask[7] + I[8]*mask[8]);
philpem@5 24638 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) {
philpem@5 24639 const double weight = (double)(I[0]*I[0] + I[1]*I[1] + I[2]*I[2] +
philpem@5 24640 I[3]*I[3] + I[4]*I[4] + I[5]*I[5] +
philpem@5 24641 I[6]*I[6] + I[7]*I[7] + I[8]*I[8]);
philpem@5 24642 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24643 }
philpem@5 24644 } break;
philpem@5 24645 case 2 : {
philpem@5 24646 T I[4] = { 0 };
philpem@5 24647 cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (Ttfloat)
philpem@5 24648 (I[0]*mask[0] + I[1]*mask[1] +
philpem@5 24649 I[2]*mask[2] + I[3]*mask[3]);
philpem@5 24650 if (weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) {
philpem@5 24651 const double weight = (double)(I[0]*I[0] + I[1]*I[1] +
philpem@5 24652 I[2]*I[2] + I[3]*I[3]);
philpem@5 24653 if (weight>0) dest(x,y,z,v)/=(Ttfloat)cimg_std::sqrt(weight);
philpem@5 24654 }
philpem@5 24655 } break;
philpem@5 24656 case 1 : (dest.assign(*this))*=mask(0); break;
philpem@5 24657 }
philpem@5 24658 }
philpem@5 24659 } else { // Generic version for other masks
philpem@5 24660 const int
philpem@5 24661 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
philpem@5 24662 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
philpem@5 24663 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
philpem@5 24664 cimg_forV(*this,v)
philpem@5 24665 if (!weighted_correl) { // Classical correlation
philpem@5 24666 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24667 Ttfloat val = 0;
philpem@5 24668 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
philpem@5 24669 val+=(*this)(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24670 dest(x,y,z,v) = (Ttfloat)val;
philpem@5 24671 }
philpem@5 24672 if (cond)
philpem@5 24673 cimg_forYZV(*this,y,z,v)
philpem@5 24674 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24675 Ttfloat val = 0;
philpem@5 24676 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
philpem@5 24677 val+=_atXYZ(x+xm,y+ym,z+zm,v)*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24678 dest(x,y,z,v) = (Ttfloat)val;
philpem@5 24679 }
philpem@5 24680 else
philpem@5 24681 cimg_forYZV(*this,y,z,v)
philpem@5 24682 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24683 Ttfloat val = 0;
philpem@5 24684 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm)
philpem@5 24685 val+=atXYZ(x+xm,y+ym,z+zm,v,0)*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24686 dest(x,y,z,v) = (Ttfloat)val;
philpem@5 24687 }
philpem@5 24688 } else { // Weighted correlation
philpem@5 24689 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24690 Ttfloat val = 0, weight = 0;
philpem@5 24691 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24692 const Ttfloat cval = (Ttfloat)(*this)(x+xm,y+ym,z+zm,v);
philpem@5 24693 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24694 weight+=cval*cval;
philpem@5 24695 }
philpem@5 24696 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
philpem@5 24697 }
philpem@5 24698 if (cond)
philpem@5 24699 cimg_forYZV(*this,y,z,v)
philpem@5 24700 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24701 Ttfloat val = 0, weight = 0;
philpem@5 24702 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24703 const Ttfloat cval = (Ttfloat)_atXYZ(x+xm,y+ym,z+zm,v);
philpem@5 24704 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24705 weight+=cval*cval;
philpem@5 24706 }
philpem@5 24707 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
philpem@5 24708 }
philpem@5 24709 else
philpem@5 24710 cimg_forYZV(*this,y,z,v)
philpem@5 24711 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24712 Ttfloat val = 0, weight = 0;
philpem@5 24713 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24714 const Ttfloat cval = (Ttfloat)atXYZ(x+xm,y+ym,z+zm,v,0);
philpem@5 24715 val+=cval*mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24716 weight+=cval*cval;
philpem@5 24717 }
philpem@5 24718 dest(x,y,z,v) = (weight>(Ttfloat)0)?(Ttfloat)(val/cimg_std::sqrt((double)weight)):(Ttfloat)0;
philpem@5 24719 }
philpem@5 24720 }
philpem@5 24721 }
philpem@5 24722 return dest;
philpem@5 24723 }
philpem@5 24724
philpem@5 24725 //! Compute the convolution of the image by a mask.
philpem@5 24726 /**
philpem@5 24727 The result \p res of the convolution of an image \p img by a mask \p mask is defined to be :
philpem@5 24728
philpem@5 24729 res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k)
philpem@5 24730
philpem@5 24731 \param mask = the correlation kernel.
philpem@5 24732 \param cond = the border condition type (0=zero, 1=dirichlet)
philpem@5 24733 \param weighted_convol = enable local normalization.
philpem@5 24734 **/
philpem@5 24735 template<typename t>
philpem@5 24736 CImg<T>& convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) {
philpem@5 24737 return get_convolve(mask,cond,weighted_convol).transfer_to(*this);
philpem@5 24738 }
philpem@5 24739
philpem@5 24740 template<typename t>
philpem@5 24741 CImg<typename cimg::superset2<T,t,float>::type> get_convolve(const CImg<t>& mask, const unsigned int cond=1,
philpem@5 24742 const bool weighted_convol=false) const {
philpem@5 24743 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 24744 if (is_empty()) return *this;
philpem@5 24745 if (!mask || mask.dim!=1)
philpem@5 24746 throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.",
philpem@5 24747 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
philpem@5 24748 return get_correlate(CImg<t>(mask.ptr(),mask.size(),1,1,1,true).get_mirror('x').resize(mask,-1),cond,weighted_convol);
philpem@5 24749 }
philpem@5 24750
philpem@5 24751 //! Return the erosion of the image by a structuring element.
philpem@5 24752 template<typename t>
philpem@5 24753 CImg<T>& erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) {
philpem@5 24754 return get_erode(mask,cond,weighted_erosion).transfer_to(*this);
philpem@5 24755 }
philpem@5 24756
philpem@5 24757 template<typename t>
philpem@5 24758 CImg<typename cimg::superset<T,t>::type> get_erode(const CImg<t>& mask, const unsigned int cond=1,
philpem@5 24759 const bool weighted_erosion=false) const {
philpem@5 24760 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 24761 if (is_empty()) return *this;
philpem@5 24762 if (!mask || mask.dim!=1)
philpem@5 24763 throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
philpem@5 24764 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
philpem@5 24765 CImg<Tt> dest(width,height,depth,dim);
philpem@5 24766 const int
philpem@5 24767 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
philpem@5 24768 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
philpem@5 24769 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
philpem@5 24770 cimg_forV(*this,v)
philpem@5 24771 if (!weighted_erosion) { // Classical erosion
philpem@5 24772 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24773 Tt min_val = cimg::type<Tt>::max();
philpem@5 24774 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24775 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
philpem@5 24776 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
philpem@5 24777 }
philpem@5 24778 dest(x,y,z,v) = min_val;
philpem@5 24779 }
philpem@5 24780 if (cond)
philpem@5 24781 cimg_forYZV(*this,y,z,v)
philpem@5 24782 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24783 Tt min_val = cimg::type<Tt>::max();
philpem@5 24784 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24785 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
philpem@5 24786 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
philpem@5 24787 }
philpem@5 24788 dest(x,y,z,v) = min_val;
philpem@5 24789 }
philpem@5 24790 else
philpem@5 24791 cimg_forYZV(*this,y,z,v)
philpem@5 24792 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24793 Tt min_val = cimg::type<Tt>::max();
philpem@5 24794 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24795 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
philpem@5 24796 if (mask(mx1+xm,my1+ym,mz1+zm) && cval<min_val) min_val = cval;
philpem@5 24797 }
philpem@5 24798 dest(x,y,z,v) = min_val;
philpem@5 24799 }
philpem@5 24800 } else { // Weighted erosion
philpem@5 24801 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24802 Tt min_val = cimg::type<Tt>::max();
philpem@5 24803 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24804 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24805 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) + mval);
philpem@5 24806 if (mval && cval<min_val) min_val = cval;
philpem@5 24807 }
philpem@5 24808 dest(x,y,z,v) = min_val;
philpem@5 24809 }
philpem@5 24810 if (cond)
philpem@5 24811 cimg_forYZV(*this,y,z,v)
philpem@5 24812 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24813 Tt min_val = cimg::type<Tt>::max();
philpem@5 24814 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24815 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24816 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) + mval);
philpem@5 24817 if (mval && cval<min_val) min_val = cval;
philpem@5 24818 }
philpem@5 24819 dest(x,y,z,v) = min_val;
philpem@5 24820 }
philpem@5 24821 else
philpem@5 24822 cimg_forYZV(*this,y,z,v)
philpem@5 24823 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24824 Tt min_val = cimg::type<Tt>::max();
philpem@5 24825 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24826 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24827 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) + mval);
philpem@5 24828 if (mval && cval<min_val) min_val = cval;
philpem@5 24829 }
philpem@5 24830 dest(x,y,z,v) = min_val;
philpem@5 24831 }
philpem@5 24832 }
philpem@5 24833 return dest;
philpem@5 24834 }
philpem@5 24835
philpem@5 24836 //! Erode the image by a square structuring element of size n.
philpem@5 24837 CImg<T>& erode(const unsigned int n, const unsigned int cond=1) {
philpem@5 24838 if (n<2) return *this;
philpem@5 24839 return get_erode(n,cond).transfer_to(*this);
philpem@5 24840 }
philpem@5 24841
philpem@5 24842 CImg<T> get_erode(const unsigned int n, const unsigned int cond=1) const {
philpem@5 24843 static CImg<T> mask;
philpem@5 24844 if (n<2) return *this;
philpem@5 24845 if (mask.width!=n) mask.assign(n,n,1,1,1);
philpem@5 24846 const CImg<T> res = get_erode(mask,cond,false);
philpem@5 24847 if (n>20) mask.assign();
philpem@5 24848 return res;
philpem@5 24849 }
philpem@5 24850
philpem@5 24851 //! Dilate the image by a structuring element.
philpem@5 24852 template<typename t>
philpem@5 24853 CImg<T>& dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) {
philpem@5 24854 return get_dilate(mask,cond,weighted_dilatation).transfer_to(*this);
philpem@5 24855 }
philpem@5 24856
philpem@5 24857 template<typename t>
philpem@5 24858 CImg<typename cimg::superset<T,t>::type> get_dilate(const CImg<t>& mask, const unsigned int cond=1,
philpem@5 24859 const bool weighted_dilatation=false) const {
philpem@5 24860 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 24861 if (is_empty()) return *this;
philpem@5 24862 if (!mask || mask.dim!=1)
philpem@5 24863 throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.",
philpem@5 24864 pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data);
philpem@5 24865 CImg<Tt> dest(width,height,depth,dim);
philpem@5 24866 const int
philpem@5 24867 mx2 = mask.dimx()/2, my2 = mask.dimy()/2, mz2 = mask.dimz()/2,
philpem@5 24868 mx1 = mx2 - 1 + (mask.dimx()%2), my1 = my2 - 1 + (mask.dimy()%2), mz1 = mz2 - 1 + (mask.dimz()%2),
philpem@5 24869 mxe = dimx() - mx2, mye = dimy() - my2, mze = dimz() - mz2;
philpem@5 24870 cimg_forV(*this,v)
philpem@5 24871 if (!weighted_dilatation) { // Classical dilatation
philpem@5 24872 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24873 Tt max_val = cimg::type<Tt>::min();
philpem@5 24874 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24875 const Tt cval = (Tt)(*this)(x+xm,y+ym,z+zm,v);
philpem@5 24876 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
philpem@5 24877 }
philpem@5 24878 dest(x,y,z,v) = max_val;
philpem@5 24879 }
philpem@5 24880 if (cond)
philpem@5 24881 cimg_forYZV(*this,y,z,v)
philpem@5 24882 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24883 Tt max_val = cimg::type<Tt>::min();
philpem@5 24884 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24885 const T cval = (Tt)_atXYZ(x+xm,y+ym,z+zm,v);
philpem@5 24886 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
philpem@5 24887 }
philpem@5 24888 dest(x,y,z,v) = max_val;
philpem@5 24889 }
philpem@5 24890 else
philpem@5 24891 cimg_forYZV(*this,y,z,v)
philpem@5 24892 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24893 Tt max_val = cimg::type<Tt>::min();
philpem@5 24894 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24895 const T cval = (Tt)atXYZ(x+xm,y+ym,z+zm,v,0);
philpem@5 24896 if (mask(mx1+xm,my1+ym,mz1+zm) && cval>max_val) max_val = cval;
philpem@5 24897 }
philpem@5 24898 dest(x,y,z,v) = max_val;
philpem@5 24899 }
philpem@5 24900 } else { // Weighted dilatation
philpem@5 24901 for (int z = mz1; z<mze; ++z) for (int y = my1; y<mye; ++y) for (int x = mx1; x<mxe; ++x) {
philpem@5 24902 Tt max_val = cimg::type<Tt>::min();
philpem@5 24903 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24904 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24905 const Tt cval = (Tt)((*this)(x+xm,y+ym,z+zm,v) - mval);
philpem@5 24906 if (mval && cval>max_val) max_val = cval;
philpem@5 24907 }
philpem@5 24908 dest(x,y,z,v) = max_val;
philpem@5 24909 }
philpem@5 24910 if (cond)
philpem@5 24911 cimg_forYZV(*this,y,z,v)
philpem@5 24912 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24913 Tt max_val = cimg::type<Tt>::min();
philpem@5 24914 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24915 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24916 const Tt cval = (Tt)(_atXYZ(x+xm,y+ym,z+zm,v) - mval);
philpem@5 24917 if (mval && cval>max_val) max_val = cval;
philpem@5 24918 }
philpem@5 24919 dest(x,y,z,v) = max_val;
philpem@5 24920 }
philpem@5 24921 else
philpem@5 24922 cimg_forYZV(*this,y,z,v)
philpem@5 24923 for (int x = 0; x<dimx(); (y<my1 || y>=mye || z<mz1 || z>=mze)?++x:((x<mx1-1 || x>=mxe)?++x:(x=mxe))) {
philpem@5 24924 Tt max_val = cimg::type<Tt>::min();
philpem@5 24925 for (int zm = -mz1; zm<=mz2; ++zm) for (int ym = -my1; ym<=my2; ++ym) for (int xm = -mx1; xm<=mx2; ++xm) {
philpem@5 24926 const t mval = mask(mx1+xm,my1+ym,mz1+zm);
philpem@5 24927 const Tt cval = (Tt)(atXYZ(x+xm,y+ym,z+zm,v,0) - mval);
philpem@5 24928 if (mval && cval>max_val) max_val = cval;
philpem@5 24929 }
philpem@5 24930 dest(x,y,z,v) = max_val;
philpem@5 24931 }
philpem@5 24932 }
philpem@5 24933 return dest;
philpem@5 24934 }
philpem@5 24935
philpem@5 24936 //! Dilate the image by a square structuring element of size n.
philpem@5 24937 CImg<T>& dilate(const unsigned int n, const unsigned int cond=1) {
philpem@5 24938 if (n<2) return *this;
philpem@5 24939 return get_dilate(n,cond).transfer_to(*this);
philpem@5 24940 }
philpem@5 24941
philpem@5 24942 CImg<T> get_dilate(const unsigned int n, const unsigned int cond=1) const {
philpem@5 24943 static CImg<T> mask;
philpem@5 24944 if (n<2) return *this;
philpem@5 24945 if (mask.width!=n) mask.assign(n,n,1,1,1);
philpem@5 24946 const CImg<T> res = get_dilate(mask,cond,false);
philpem@5 24947 if (n>20) mask.assign();
philpem@5 24948 return res;
philpem@5 24949 }
philpem@5 24950
philpem@5 24951 //! Add noise to the image.
philpem@5 24952 /**
philpem@5 24953 \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value.
philpem@5 24954 \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper, 3=Poisson, 4=Rician.
philpem@5 24955 \return A noisy version of the instance image.
philpem@5 24956 **/
philpem@5 24957 CImg<T>& noise(const double sigma, const unsigned int noise_type=0) {
philpem@5 24958 if (!is_empty()) {
philpem@5 24959 double nsigma = sigma, max = (double)cimg::type<T>::max(), min = (double)cimg::type<T>::min();
philpem@5 24960 Tfloat m = 0, M = 0;
philpem@5 24961 if (nsigma==0 && noise_type!=3) return *this;
philpem@5 24962 if (nsigma<0 || noise_type==2) m = (Tfloat)minmax(M);
philpem@5 24963 if (nsigma<0) nsigma = -nsigma*(M-m)/100.0;
philpem@5 24964 switch (noise_type) {
philpem@5 24965 case 0 : { // Gaussian noise
philpem@5 24966 cimg_for(*this,ptr,T) {
philpem@5 24967 double val = *ptr + nsigma*cimg::grand();
philpem@5 24968 if (val>max) val = max;
philpem@5 24969 if (val<min) val = min;
philpem@5 24970 *ptr = (T)val;
philpem@5 24971 }
philpem@5 24972 } break;
philpem@5 24973 case 1 : { // Uniform noise
philpem@5 24974 cimg_for(*this,ptr,T) {
philpem@5 24975 double val = *ptr + nsigma*cimg::crand();
philpem@5 24976 if (val>max) val = max;
philpem@5 24977 if (val<min) val = min;
philpem@5 24978 *ptr = (T)val;
philpem@5 24979 }
philpem@5 24980 } break;
philpem@5 24981 case 2 : { // Salt & Pepper noise
philpem@5 24982 if (nsigma<0) nsigma = -nsigma;
philpem@5 24983 if (M==m) { m = 0; M = (float)(cimg::type<T>::is_float()?1:cimg::type<T>::max()); }
philpem@5 24984 cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr = (T)(cimg::rand()<0.5?M:m);
philpem@5 24985 } break;
philpem@5 24986
philpem@5 24987 case 3 : { // Poisson Noise
philpem@5 24988 cimg_for(*this,ptr,T) *ptr = (T)cimg::prand(*ptr);
philpem@5 24989 } break;
philpem@5 24990
philpem@5 24991 case 4 : { // Rice noise
philpem@5 24992 const double sqrt2 = (double)cimg_std::sqrt(2.0);
philpem@5 24993 cimg_for(*this,ptr,T) {
philpem@5 24994 const double
philpem@5 24995 val0 = (double)*ptr/sqrt2,
philpem@5 24996 re = val0 + nsigma*cimg::grand(),
philpem@5 24997 im = val0 + nsigma*cimg::grand();
philpem@5 24998 double val = cimg_std::sqrt(re*re + im*im);
philpem@5 24999 if (val>max) val = max;
philpem@5 25000 if (val<min) val = min;
philpem@5 25001 *ptr = (T)val;
philpem@5 25002 }
philpem@5 25003 } break;
philpem@5 25004 default :
philpem@5 25005 throw CImgArgumentException("CImg<%s>::noise() : Invalid noise type %d "
philpem@5 25006 "(should be {0=Gaussian, 1=Uniform, 2=Salt&Pepper, 3=Poisson}).",pixel_type(),noise_type);
philpem@5 25007 }
philpem@5 25008 }
philpem@5 25009 return *this;
philpem@5 25010 }
philpem@5 25011
philpem@5 25012 CImg<T> get_noise(const double sigma, const unsigned int noise_type=0) const {
philpem@5 25013 return (+*this).noise(sigma,noise_type);
philpem@5 25014 }
philpem@5 25015
philpem@5 25016 //! Compute the result of the Deriche filter.
philpem@5 25017 /**
philpem@5 25018 The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of
philpem@5 25019 order 0,1 or 2 of an image.
philpem@5 25020 **/
philpem@5 25021 CImg<T>& deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) {
philpem@5 25022 #define _cimg_deriche2_apply \
philpem@5 25023 Tfloat *ptrY = Y.data, yb = 0, yp = 0; \
philpem@5 25024 T xp = (T)0; \
philpem@5 25025 if (cond) { xp = *ptrX; yb = yp = (Tfloat)(coefp*xp); } \
philpem@5 25026 for (int m=0; m<N; ++m) { \
philpem@5 25027 const T xc = *ptrX; ptrX+=off; \
philpem@5 25028 const Tfloat yc = *(ptrY++) = (Tfloat)(a0*xc + a1*xp - b1*yp - b2*yb); \
philpem@5 25029 xp = xc; yb = yp; yp = yc; \
philpem@5 25030 } \
philpem@5 25031 T xn = (T)0, xa = (T)0; \
philpem@5 25032 Tfloat yn = 0, ya = 0; \
philpem@5 25033 if (cond) { xn = xa = *(ptrX-off); yn = ya = (Tfloat)coefn*xn; } \
philpem@5 25034 for (int n=N-1; n>=0; --n) { \
philpem@5 25035 const T xc = *(ptrX-=off); \
philpem@5 25036 const Tfloat yc = (Tfloat)(a2*xn + a3*xa - b1*yn - b2*ya); \
philpem@5 25037 xa = xn; xn = xc; ya = yn; yn = yc; \
philpem@5 25038 *ptrX = (T)(*(--ptrY)+yc); \
philpem@5 25039 }
philpem@5 25040 if (sigma<0)
philpem@5 25041 throw CImgArgumentException("CImg<%s>::deriche() : Given filter variance (sigma = %g) is negative",
philpem@5 25042 pixel_type(),sigma);
philpem@5 25043 if (is_empty() || (sigma<0.1 && !order)) return *this;
philpem@5 25044 const float
philpem@5 25045 nsigma = sigma<0.1f?0.1f:sigma,
philpem@5 25046 alpha = 1.695f/nsigma,
philpem@5 25047 ema = (float)cimg_std::exp(-alpha),
philpem@5 25048 ema2 = (float)cimg_std::exp(-2*alpha),
philpem@5 25049 b1 = -2*ema,
philpem@5 25050 b2 = ema2;
philpem@5 25051 float a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0;
philpem@5 25052 switch (order) {
philpem@5 25053 case 0 : {
philpem@5 25054 const float k = (1-ema)*(1-ema)/(1+2*alpha*ema-ema2);
philpem@5 25055 a0 = k;
philpem@5 25056 a1 = k*(alpha-1)*ema;
philpem@5 25057 a2 = k*(alpha+1)*ema;
philpem@5 25058 a3 = -k*ema2;
philpem@5 25059 } break;
philpem@5 25060 case 1 : {
philpem@5 25061 const float k = (1-ema)*(1-ema)/ema;
philpem@5 25062 a0 = k*ema;
philpem@5 25063 a1 = a3 = 0;
philpem@5 25064 a2 = -a0;
philpem@5 25065 } break;
philpem@5 25066 case 2 : {
philpem@5 25067 const float
philpem@5 25068 ea = (float)cimg_std::exp(-alpha),
philpem@5 25069 k = -(ema2-1)/(2*alpha*ema),
philpem@5 25070 kn = (-2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea));
philpem@5 25071 a0 = kn;
philpem@5 25072 a1 = -kn*(1+k*alpha)*ema;
philpem@5 25073 a2 = kn*(1-k*alpha)*ema;
philpem@5 25074 a3 = -kn*ema2;
philpem@5 25075 } break;
philpem@5 25076 default :
philpem@5 25077 throw CImgArgumentException("CImg<%s>::deriche() : Given filter order (order = %u) must be 0,1 or 2",
philpem@5 25078 pixel_type(),order);
philpem@5 25079 }
philpem@5 25080 coefp = (a0+a1)/(1+b1+b2);
philpem@5 25081 coefn = (a2+a3)/(1+b1+b2);
philpem@5 25082 switch (cimg::uncase(axis)) {
philpem@5 25083 case 'x' : {
philpem@5 25084 const int N = width, off = 1;
philpem@5 25085 CImg<Tfloat> Y(N);
philpem@5 25086 cimg_forYZV(*this,y,z,v) { T *ptrX = ptr(0,y,z,v); _cimg_deriche2_apply; }
philpem@5 25087 } break;
philpem@5 25088 case 'y' : {
philpem@5 25089 const int N = height, off = width;
philpem@5 25090 CImg<Tfloat> Y(N);
philpem@5 25091 cimg_forXZV(*this,x,z,v) { T *ptrX = ptr(x,0,z,v); _cimg_deriche2_apply; }
philpem@5 25092 } break;
philpem@5 25093 case 'z' : {
philpem@5 25094 const int N = depth, off = width*height;
philpem@5 25095 CImg<Tfloat> Y(N);
philpem@5 25096 cimg_forXYV(*this,x,y,v) { T *ptrX = ptr(x,y,0,v); _cimg_deriche2_apply; }
philpem@5 25097 } break;
philpem@5 25098 case 'v' : {
philpem@5 25099 const int N = dim, off = width*height*depth;
philpem@5 25100 CImg<Tfloat> Y(N);
philpem@5 25101 cimg_forXYZ(*this,x,y,z) { T *ptrX = ptr(x,y,z,0); _cimg_deriche2_apply; }
philpem@5 25102 } break;
philpem@5 25103 }
philpem@5 25104 return *this;
philpem@5 25105 }
philpem@5 25106
philpem@5 25107 CImg<Tfloat> get_deriche(const float sigma, const int order=0, const char axis='x', const bool cond=true) const {
philpem@5 25108 return CImg<Tfloat>(*this,false).deriche(sigma,order,axis,cond);
philpem@5 25109 }
philpem@5 25110
philpem@5 25111 //! Return a blurred version of the image, using a Canny-Deriche filter.
philpem@5 25112 /**
philpem@5 25113 Blur the image with an anisotropic exponential filter (Deriche filter of order 0).
philpem@5 25114 **/
philpem@5 25115 CImg<T>& blur(const float sigmax, const float sigmay, const float sigmaz, const bool cond=true) {
philpem@5 25116 if (!is_empty()) {
philpem@5 25117 if (width>1 && sigmax>0) deriche(sigmax,0,'x',cond);
philpem@5 25118 if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond);
philpem@5 25119 if (depth>1 && sigmaz>0) deriche(sigmaz,0,'z',cond);
philpem@5 25120 }
philpem@5 25121 return *this;
philpem@5 25122 }
philpem@5 25123
philpem@5 25124 CImg<Tfloat> get_blur(const float sigmax, const float sigmay, const float sigmaz,
philpem@5 25125 const bool cond=true) const {
philpem@5 25126 return CImg<Tfloat>(*this,false).blur(sigmax,sigmay,sigmaz,cond);
philpem@5 25127 }
philpem@5 25128
philpem@5 25129 //! Return a blurred version of the image, using a Canny-Deriche filter.
philpem@5 25130 CImg<T>& blur(const float sigma, const bool cond=true) {
philpem@5 25131 return blur(sigma,sigma,sigma,cond);
philpem@5 25132 }
philpem@5 25133
philpem@5 25134 CImg<Tfloat> get_blur(const float sigma, const bool cond=true) const {
philpem@5 25135 return CImg<Tfloat>(*this,false).blur(sigma,cond);
philpem@5 25136 }
philpem@5 25137
philpem@5 25138 //! Blur the image anisotropically following a field of diffusion tensors.
philpem@5 25139 /**
philpem@5 25140 \param G = Field of square roots of diffusion tensors used to drive the smoothing.
philpem@5 25141 \param amplitude = amplitude of the smoothing.
philpem@5 25142 \param dl = spatial discretization.
philpem@5 25143 \param da = angular discretization.
philpem@5 25144 \param gauss_prec = precision of the gaussian function.
philpem@5 25145 \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
philpem@5 25146 \param fast_approx = Tell to use the fast approximation or not.
philpem@5 25147 **/
philpem@5 25148 template<typename t>
philpem@5 25149 CImg<T>& blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
philpem@5 25150 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) {
philpem@5 25151 #define _cimg_valign2d(i,j) \
philpem@5 25152 { Tfloat &u = W(i,j,0,0), &v = W(i,j,0,1); \
philpem@5 25153 if (u*curru + v*currv<0) { u=-u; v=-v; }}
philpem@5 25154 #define _cimg_valign3d(i,j,k) \
philpem@5 25155 { Tfloat &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \
philpem@5 25156 if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }}
philpem@5 25157
philpem@5 25158 // Check arguments and init variables
philpem@5 25159 if (!is_empty() && amplitude>0) {
philpem@5 25160 if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth)
philpem@5 25161 throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.",
philpem@5 25162 pixel_type(),G.width,G.height,G.depth,G.dim);
philpem@5 25163
philpem@5 25164 const float sqrt2amplitude = (float)cimg_std::sqrt(2*amplitude);
philpem@5 25165 const bool threed = (G.dim>=6);
philpem@5 25166 const int
philpem@5 25167 dx1 = dimx()-1,
philpem@5 25168 dy1 = dimy()-1,
philpem@5 25169 dz1 = dimz()-1;
philpem@5 25170 CImg<Tfloat>
philpem@5 25171 dest(width,height,depth,dim,0),
philpem@5 25172 W(width,height,depth,threed?4:3),
philpem@5 25173 tmp(dim);
philpem@5 25174 int N = 0;
philpem@5 25175
philpem@5 25176 if (threed)
philpem@5 25177 // 3D version of the algorithm
philpem@5 25178 for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) {
philpem@5 25179 const float
philpem@5 25180 phir = (float)(phi*cimg::valuePI/180),
philpem@5 25181 datmp = (float)(da/cimg_std::cos(phir)),
philpem@5 25182 da2 = datmp<1?360.0f:datmp;
philpem@5 25183
philpem@5 25184 for (float theta=0; theta<360; (theta+=da2),++N) {
philpem@5 25185 const float
philpem@5 25186 thetar = (float)(theta*cimg::valuePI/180),
philpem@5 25187 vx = (float)(cimg_std::cos(thetar)*cimg_std::cos(phir)),
philpem@5 25188 vy = (float)(cimg_std::sin(thetar)*cimg_std::cos(phir)),
philpem@5 25189 vz = (float)cimg_std::sin(phir);
philpem@5 25190 const t
philpem@5 25191 *pa = G.ptr(0,0,0,0),
philpem@5 25192 *pb = G.ptr(0,0,0,1),
philpem@5 25193 *pc = G.ptr(0,0,0,2),
philpem@5 25194 *pd = G.ptr(0,0,0,3),
philpem@5 25195 *pe = G.ptr(0,0,0,4),
philpem@5 25196 *pf = G.ptr(0,0,0,5);
philpem@5 25197 Tfloat
philpem@5 25198 *pd0 = W.ptr(0,0,0,0),
philpem@5 25199 *pd1 = W.ptr(0,0,0,1),
philpem@5 25200 *pd2 = W.ptr(0,0,0,2),
philpem@5 25201 *pd3 = W.ptr(0,0,0,3);
philpem@5 25202 cimg_forXYZ(G,xg,yg,zg) {
philpem@5 25203 const t
philpem@5 25204 a = *(pa++), b = *(pb++), c = *(pc++),
philpem@5 25205 d = *(pd++), e = *(pe++), f = *(pf++);
philpem@5 25206 const float
philpem@5 25207 u = (float)(a*vx + b*vy + c*vz),
philpem@5 25208 v = (float)(b*vx + d*vy + e*vz),
philpem@5 25209 w = (float)(c*vx + e*vy + f*vz),
philpem@5 25210 n = (float)cimg_std::sqrt(1e-5+u*u+v*v+w*w),
philpem@5 25211 dln = dl/n;
philpem@5 25212 *(pd0++) = (Tfloat)(u*dln);
philpem@5 25213 *(pd1++) = (Tfloat)(v*dln);
philpem@5 25214 *(pd2++) = (Tfloat)(w*dln);
philpem@5 25215 *(pd3++) = (Tfloat)n;
philpem@5 25216 }
philpem@5 25217
philpem@5 25218 cimg_forXYZ(*this,x,y,z) {
philpem@5 25219 tmp.fill(0);
philpem@5 25220 const float
philpem@5 25221 cu = (float)W(x,y,z,0),
philpem@5 25222 cv = (float)W(x,y,z,1),
philpem@5 25223 cw = (float)W(x,y,z,2),
philpem@5 25224 n = (float)W(x,y,z,3),
philpem@5 25225 fsigma = (float)(n*sqrt2amplitude),
philpem@5 25226 length = gauss_prec*fsigma,
philpem@5 25227 fsigma2 = 2*fsigma*fsigma;
philpem@5 25228 float
philpem@5 25229 S = 0,
philpem@5 25230 pu = cu,
philpem@5 25231 pv = cv,
philpem@5 25232 pw = cw,
philpem@5 25233 X = (float)x,
philpem@5 25234 Y = (float)y,
philpem@5 25235 Z = (float)z;
philpem@5 25236
philpem@5 25237 switch (interpolation_type) {
philpem@5 25238 case 0 : {
philpem@5 25239 // Nearest neighbor
philpem@5 25240 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
philpem@5 25241 const int
philpem@5 25242 cx = (int)(X+0.5f),
philpem@5 25243 cy = (int)(Y+0.5f),
philpem@5 25244 cz = (int)(Z+0.5f);
philpem@5 25245 float
philpem@5 25246 u = (float)W(cx,cy,cz,0),
philpem@5 25247 v = (float)W(cx,cy,cz,1),
philpem@5 25248 w = (float)W(cx,cy,cz,2);
philpem@5 25249 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
philpem@5 25250 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,cz,k); ++S; }
philpem@5 25251 else {
philpem@5 25252 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25253 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,cz,k));
philpem@5 25254 S+=coef;
philpem@5 25255 }
philpem@5 25256 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
philpem@5 25257 }
philpem@5 25258 } break;
philpem@5 25259
philpem@5 25260 case 1 : {
philpem@5 25261 // Linear interpolation
philpem@5 25262 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
philpem@5 25263 const int
philpem@5 25264 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
philpem@5 25265 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
philpem@5 25266 cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
philpem@5 25267 const float
philpem@5 25268 curru = (float)W(cx,cy,cz,0),
philpem@5 25269 currv = (float)W(cx,cy,cz,1),
philpem@5 25270 currw = (float)W(cx,cy,cz,2);
philpem@5 25271 _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
philpem@5 25272 _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
philpem@5 25273 _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
philpem@5 25274 _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
philpem@5 25275 _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
philpem@5 25276 _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
philpem@5 25277 _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
philpem@5 25278 _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
philpem@5 25279 _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
philpem@5 25280 float
philpem@5 25281 u = (float)(W._linear_atXYZ(X,Y,Z,0)),
philpem@5 25282 v = (float)(W._linear_atXYZ(X,Y,Z,1)),
philpem@5 25283 w = (float)(W._linear_atXYZ(X,Y,Z,2));
philpem@5 25284 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
philpem@5 25285 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
philpem@5 25286 else {
philpem@5 25287 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25288 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
philpem@5 25289 S+=coef;
philpem@5 25290 }
philpem@5 25291 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
philpem@5 25292 }
philpem@5 25293 } break;
philpem@5 25294
philpem@5 25295 default : {
philpem@5 25296 // 2nd order Runge Kutta
philpem@5 25297 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) {
philpem@5 25298 const int
philpem@5 25299 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
philpem@5 25300 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1,
philpem@5 25301 cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1;
philpem@5 25302 const float
philpem@5 25303 curru = (float)W(cx,cy,cz,0),
philpem@5 25304 currv = (float)W(cx,cy,cz,1),
philpem@5 25305 currw = (float)W(cx,cy,cz,2);
philpem@5 25306 _cimg_valign3d(px,py,pz); _cimg_valign3d(cx,py,pz); _cimg_valign3d(nx,py,pz);
philpem@5 25307 _cimg_valign3d(px,cy,pz); _cimg_valign3d(cx,cy,pz); _cimg_valign3d(nx,cy,pz);
philpem@5 25308 _cimg_valign3d(px,ny,pz); _cimg_valign3d(cx,ny,pz); _cimg_valign3d(nx,ny,pz);
philpem@5 25309 _cimg_valign3d(px,py,cz); _cimg_valign3d(cx,py,cz); _cimg_valign3d(nx,py,cz);
philpem@5 25310 _cimg_valign3d(px,cy,cz); _cimg_valign3d(nx,cy,cz);
philpem@5 25311 _cimg_valign3d(px,ny,cz); _cimg_valign3d(cx,ny,cz); _cimg_valign3d(nx,ny,cz);
philpem@5 25312 _cimg_valign3d(px,py,nz); _cimg_valign3d(cx,py,nz); _cimg_valign3d(nx,py,nz);
philpem@5 25313 _cimg_valign3d(px,cy,nz); _cimg_valign3d(cx,cy,nz); _cimg_valign3d(nx,cy,nz);
philpem@5 25314 _cimg_valign3d(px,ny,nz); _cimg_valign3d(cx,ny,nz); _cimg_valign3d(nx,ny,nz);
philpem@5 25315 const float
philpem@5 25316 u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)),
philpem@5 25317 v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)),
philpem@5 25318 w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2));
philpem@5 25319 float
philpem@5 25320 u = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,0)),
philpem@5 25321 v = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,1)),
philpem@5 25322 w = (float)(W._linear_atXYZ(X+u0,Y+v0,Z+w0,2));
philpem@5 25323 if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; }
philpem@5 25324 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXYZ(X,Y,Z,k); ++S; }
philpem@5 25325 else {
philpem@5 25326 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25327 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,k));
philpem@5 25328 S+=coef;
philpem@5 25329 }
philpem@5 25330 X+=(pu=u); Y+=(pv=v); Z+=(pw=w);
philpem@5 25331 }
philpem@5 25332 } break;
philpem@5 25333 }
philpem@5 25334 if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S;
philpem@5 25335 else cimg_forV(dest,k) dest(x,y,z,k)+=(Tfloat)((*this)(x,y,z,k));
philpem@5 25336 cimg_plugin_greycstoration_count;
philpem@5 25337 }
philpem@5 25338 }
philpem@5 25339 } else
philpem@5 25340 // 2D version of the algorithm
philpem@5 25341 for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),++N) {
philpem@5 25342 const float
philpem@5 25343 thetar = (float)(theta*cimg::valuePI/180),
philpem@5 25344 vx = (float)(cimg_std::cos(thetar)),
philpem@5 25345 vy = (float)(cimg_std::sin(thetar));
philpem@5 25346 const t
philpem@5 25347 *pa = G.ptr(0,0,0,0),
philpem@5 25348 *pb = G.ptr(0,0,0,1),
philpem@5 25349 *pc = G.ptr(0,0,0,2);
philpem@5 25350 Tfloat
philpem@5 25351 *pd0 = W.ptr(0,0,0,0),
philpem@5 25352 *pd1 = W.ptr(0,0,0,1),
philpem@5 25353 *pd2 = W.ptr(0,0,0,2);
philpem@5 25354 cimg_forXY(G,xg,yg) {
philpem@5 25355 const t a = *(pa++), b = *(pb++), c = *(pc++);
philpem@5 25356 const float
philpem@5 25357 u = (float)(a*vx + b*vy),
philpem@5 25358 v = (float)(b*vx + c*vy),
philpem@5 25359 n = (float)cimg_std::sqrt(1e-5+u*u+v*v),
philpem@5 25360 dln = dl/n;
philpem@5 25361 *(pd0++) = (Tfloat)(u*dln);
philpem@5 25362 *(pd1++) = (Tfloat)(v*dln);
philpem@5 25363 *(pd2++) = (Tfloat)n;
philpem@5 25364 }
philpem@5 25365
philpem@5 25366 cimg_forXY(*this,x,y) {
philpem@5 25367 tmp.fill(0);
philpem@5 25368 const float
philpem@5 25369 cu = (float)W(x,y,0,0),
philpem@5 25370 cv = (float)W(x,y,0,1),
philpem@5 25371 n = (float)W(x,y,0,2),
philpem@5 25372 fsigma = (float)(n*sqrt2amplitude),
philpem@5 25373 length = gauss_prec*fsigma,
philpem@5 25374 fsigma2 = 2*fsigma*fsigma;
philpem@5 25375 float
philpem@5 25376 S = 0,
philpem@5 25377 pu = cu,
philpem@5 25378 pv = cv,
philpem@5 25379 X = (float)x,
philpem@5 25380 Y = (float)y;
philpem@5 25381
philpem@5 25382 switch (interpolation_type) {
philpem@5 25383
philpem@5 25384 case 0 : {
philpem@5 25385 // Nearest-neighbor interpolation for 2D images
philpem@5 25386 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
philpem@5 25387 const int
philpem@5 25388 cx = (int)(X+0.5f),
philpem@5 25389 cy = (int)(Y+0.5f);
philpem@5 25390 float
philpem@5 25391 u = (float)W(cx,cy,0,0),
philpem@5 25392 v = (float)W(cx,cy,0,1);
philpem@5 25393 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
philpem@5 25394 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)(*this)(cx,cy,0,k); ++S; }
philpem@5 25395 else {
philpem@5 25396 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25397 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*(*this)(cx,cy,0,k));
philpem@5 25398 S+=coef;
philpem@5 25399 }
philpem@5 25400 X+=(pu=u); Y+=(pv=v);
philpem@5 25401 }
philpem@5 25402 } break;
philpem@5 25403
philpem@5 25404 case 1 : {
philpem@5 25405 // Linear interpolation for 2D images
philpem@5 25406 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
philpem@5 25407 const int
philpem@5 25408 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
philpem@5 25409 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
philpem@5 25410 const float
philpem@5 25411 curru = (float)W(cx,cy,0,0),
philpem@5 25412 currv = (float)W(cx,cy,0,1);
philpem@5 25413 _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
philpem@5 25414 _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
philpem@5 25415 _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
philpem@5 25416 float
philpem@5 25417 u = (float)(W._linear_atXY(X,Y,0,0)),
philpem@5 25418 v = (float)(W._linear_atXY(X,Y,0,1));
philpem@5 25419 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
philpem@5 25420 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
philpem@5 25421 else {
philpem@5 25422 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25423 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
philpem@5 25424 S+=coef;
philpem@5 25425 }
philpem@5 25426 X+=(pu=u); Y+=(pv=v);
philpem@5 25427 }
philpem@5 25428 } break;
philpem@5 25429
philpem@5 25430 default : {
philpem@5 25431 // 2nd-order Runge-kutta interpolation for 2D images
philpem@5 25432 for (float l=0; l<length && X>=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) {
philpem@5 25433 const int
philpem@5 25434 cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1,
philpem@5 25435 cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1;
philpem@5 25436 const float
philpem@5 25437 curru = (float)W(cx,cy,0,0),
philpem@5 25438 currv = (float)W(cx,cy,0,1);
philpem@5 25439 _cimg_valign2d(px,py); _cimg_valign2d(cx,py); _cimg_valign2d(nx,py);
philpem@5 25440 _cimg_valign2d(px,cy); _cimg_valign2d(nx,cy);
philpem@5 25441 _cimg_valign2d(px,ny); _cimg_valign2d(cx,ny); _cimg_valign2d(nx,ny);
philpem@5 25442 const float
philpem@5 25443 u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)),
philpem@5 25444 v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1));
philpem@5 25445 float
philpem@5 25446 u = (float)(W._linear_atXY(X+u0,Y+v0,0,0)),
philpem@5 25447 v = (float)(W._linear_atXY(X+u0,Y+v0,0,1));
philpem@5 25448 if ((pu*u + pv*v)<0) { u=-u; v=-v; }
philpem@5 25449 if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(Tfloat)_linear_atXY(X,Y,0,k); ++S; }
philpem@5 25450 else {
philpem@5 25451 const float coef = (float)cimg_std::exp(-l*l/fsigma2);
philpem@5 25452 cimg_forV(*this,k) tmp[k]+=(Tfloat)(coef*_linear_atXY(X,Y,0,k));
philpem@5 25453 S+=coef;
philpem@5 25454 }
philpem@5 25455 X+=(pu=u); Y+=(pv=v);
philpem@5 25456 }
philpem@5 25457 }
philpem@5 25458 }
philpem@5 25459 if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S;
philpem@5 25460 else cimg_forV(dest,k) dest(x,y,0,k)+=(Tfloat)((*this)(x,y,0,k));
philpem@5 25461 cimg_plugin_greycstoration_count;
philpem@5 25462 }
philpem@5 25463 }
philpem@5 25464 const Tfloat *ptrs = dest.data+dest.size();
philpem@5 25465 const T m = cimg::type<T>::min(), M = cimg::type<T>::max();
philpem@5 25466 cimg_for(*this,ptrd,T) { const Tfloat val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?M:(T)val); }
philpem@5 25467 }
philpem@5 25468 return *this;
philpem@5 25469 }
philpem@5 25470
philpem@5 25471 template<typename t>
philpem@5 25472 CImg<T> get_blur_anisotropic(const CImg<t>& G, const float amplitude=60, const float dl=0.8f, const float da=30,
philpem@5 25473 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true) const {
philpem@5 25474 return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
philpem@5 25475 }
philpem@5 25476
philpem@5 25477 //! Blur an image in an anisotropic way.
philpem@5 25478 /**
philpem@5 25479 \param mask Binary mask.
philpem@5 25480 \param amplitude Amplitude of the anisotropic blur.
philpem@5 25481 \param sharpness Contour preservation.
philpem@5 25482 \param anisotropy Smoothing anisotropy.
philpem@5 25483 \param alpha Image pre-blurring (gaussian).
philpem@5 25484 \param sigma Regularity of the tensor-valued geometry.
philpem@5 25485 \param dl Spatial discretization.
philpem@5 25486 \param da Angular discretization.
philpem@5 25487 \param gauss_prec Precision of the gaussian function.
philpem@5 25488 \param interpolation_type Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta)
philpem@5 25489 \param fast_approx Tell to use the fast approximation or not
philpem@5 25490 \param geom_factor Geometry factor.
philpem@5 25491 **/
philpem@5 25492 template<typename tm>
philpem@5 25493 CImg<T>& blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
philpem@5 25494 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
philpem@5 25495 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
philpem@5 25496 const float geom_factor=1) {
philpem@5 25497 if (!is_empty() && amplitude>0) {
philpem@5 25498 if (amplitude==0) return *this;
philpem@5 25499 if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0)
philpem@5 25500 throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), "
philpem@5 25501 "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n"
philpem@5 25502 "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], "
philpem@5 25503 "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.",
philpem@5 25504 pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec);
philpem@5 25505 const bool threed = (depth>1), no_mask = mask.is_empty();
philpem@5 25506 const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1-anisotropy);
philpem@5 25507 CImg<floatT> blurred = CImg<floatT>(*this,false).blur(alpha);
philpem@5 25508 if (geom_factor>0) blurred*=geom_factor;
philpem@5 25509 else blurred.normalize(0,-geom_factor);
philpem@5 25510
philpem@5 25511 if (threed) { // Field for 3D volumes
philpem@5 25512 cimg_plugin_greycstoration_lock;
philpem@5 25513 CImg<floatT> val(3), vec(3,3), G(blurred.get_structure_tensor());
philpem@5 25514 if (sigma>0) G.blur(sigma);
philpem@5 25515 cimg_forXYZ(*this,x,y,z) {
philpem@5 25516 if (no_mask || mask(x,y,z)) {
philpem@5 25517 G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
philpem@5 25518 const float l1 = val[2], l2 = val[1], l3 = val[0],
philpem@5 25519 ux = vec(0,0), uy = vec(0,1), uz = vec(0,2),
philpem@5 25520 vx = vec(1,0), vy = vec(1,1), vz = vec(1,2),
philpem@5 25521 wx = vec(2,0), wy = vec(2,1), wz = vec(2,2),
philpem@5 25522 n1 = (float)cimg_std::pow(1+l1+l2+l3,-power1),
philpem@5 25523 n2 = (float)cimg_std::pow(1+l1+l2+l3,-power2);
philpem@5 25524 G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx;
philpem@5 25525 G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy;
philpem@5 25526 G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz;
philpem@5 25527 G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy;
philpem@5 25528 G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz;
philpem@5 25529 G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz;
philpem@5 25530 } else G(x,y,z,0) = G(x,y,z,1) = G(x,y,z,2) = G(x,y,z,3) = G(x,y,z,4) = G(x,y,z,5) = 0;
philpem@5 25531 cimg_plugin_greycstoration_count;
philpem@5 25532 }
philpem@5 25533 cimg_plugin_greycstoration_unlock;
philpem@5 25534 blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
philpem@5 25535 } else { // Field for 2D images
philpem@5 25536 cimg_plugin_greycstoration_lock;
philpem@5 25537 CImg<floatT> val(2), vec(2,2), G(blurred.get_structure_tensor());
philpem@5 25538 if (sigma>0) G.blur(sigma);
philpem@5 25539 cimg_forXY(*this,x,y) {
philpem@5 25540 if (no_mask || mask(x,y)) {
philpem@5 25541 G.get_tensor_at(x,y).symmetric_eigen(val,vec);
philpem@5 25542 const float l1 = val[1], l2 = val[0],
philpem@5 25543 ux = vec(1,0), uy = vec(1,1),
philpem@5 25544 vx = vec(0,0), vy = vec(0,1),
philpem@5 25545 n1 = (float)cimg_std::pow(1+l1+l2,-power1),
philpem@5 25546 n2 = (float)cimg_std::pow(1+l1+l2,-power2);
philpem@5 25547 G(x,y,0,0) = n1*ux*ux + n2*vx*vx;
philpem@5 25548 G(x,y,0,1) = n1*ux*uy + n2*vx*vy;
philpem@5 25549 G(x,y,0,2) = n1*uy*uy + n2*vy*vy;
philpem@5 25550 } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0;
philpem@5 25551 cimg_plugin_greycstoration_count;
philpem@5 25552 }
philpem@5 25553 cimg_plugin_greycstoration_unlock;
philpem@5 25554 blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,fast_approx);
philpem@5 25555 }
philpem@5 25556 }
philpem@5 25557 return *this;
philpem@5 25558 }
philpem@5 25559
philpem@5 25560 template<typename tm>
philpem@5 25561 CImg<T> get_blur_anisotropic(const CImg<tm>& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
philpem@5 25562 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
philpem@5 25563 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
philpem@5 25564 const bool fast_approx=true, const float geom_factor=1) const {
philpem@5 25565 return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
philpem@5 25566 }
philpem@5 25567
philpem@5 25568 //! Blur an image following in an anisotropic way.
philpem@5 25569 CImg<T>& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
philpem@5 25570 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30,
philpem@5 25571 const float gauss_prec=2, const unsigned int interpolation_type=0, const bool fast_approx=true,
philpem@5 25572 const float geom_factor=1) {
philpem@5 25573 return blur_anisotropic(CImg<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
philpem@5 25574 }
philpem@5 25575
philpem@5 25576 CImg<T> get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f,
philpem@5 25577 const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,
philpem@5 25578 const float da=30, const float gauss_prec=2, const unsigned int interpolation_type=0,
philpem@5 25579 const bool fast_approx=true, const float geom_factor=1) const {
philpem@5 25580 return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation_type,fast_approx,geom_factor);
philpem@5 25581 }
philpem@5 25582
philpem@5 25583 //! Blur an image using the bilateral filter.
philpem@5 25584 /**
philpem@5 25585 \param sigmax Amount of blur along the X-axis.
philpem@5 25586 \param sigmay Amount of blur along the Y-axis.
philpem@5 25587 \param sigmaz Amount of blur along the Z-axis.
philpem@5 25588 \param sigmar Amount of blur along the range axis.
philpem@5 25589 \param bgridx Size of the bilateral grid along the X-axis.
philpem@5 25590 \param bgridy Size of the bilateral grid along the Y-axis.
philpem@5 25591 \param bgridz Size of the bilateral grid along the Z-axis.
philpem@5 25592 \param bgridr Size of the bilateral grid along the range axis.
philpem@5 25593 \param interpolation_type Use interpolation for image slicing.
philpem@5 25594 \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006
philpem@5 25595 (extended for 3D volumetric images).
philpem@5 25596 **/
philpem@5 25597 CImg<T>& blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
philpem@5 25598 const int bgridx, const int bgridy, const int bgridz, const int bgridr,
philpem@5 25599 const bool interpolation_type=true) {
philpem@5 25600 T m, M = maxmin(m);
philpem@5 25601 const float range = (float)(1.0f+M-m);
philpem@5 25602 const unsigned int
philpem@5 25603 bx0 = bgridx>=0?bgridx:width*(-bgridx)/100,
philpem@5 25604 by0 = bgridy>=0?bgridy:height*(-bgridy)/100,
philpem@5 25605 bz0 = bgridz>=0?bgridz:depth*(-bgridz)/100,
philpem@5 25606 br0 = bgridr>=0?bgridr:(int)(-range*bgridr/100),
philpem@5 25607 bx = bx0>0?bx0:1,
philpem@5 25608 by = by0>0?by0:1,
philpem@5 25609 bz = bz0>0?bz0:1,
philpem@5 25610 br = br0>0?br0:1;
philpem@5 25611 const float
philpem@5 25612 nsigmax = sigmax*bx/width,
philpem@5 25613 nsigmay = sigmay*by/height,
philpem@5 25614 nsigmaz = sigmaz*bz/depth,
philpem@5 25615 nsigmar = sigmar*br/range;
philpem@5 25616 if (nsigmax>0 || nsigmay>0 || nsigmaz>0 || nsigmar>0) {
philpem@5 25617 const bool threed = depth>1;
philpem@5 25618 if (threed) { // 3d version of the algorithm
philpem@5 25619 CImg<floatT> bgrid(bx,by,bz,br), bgridw(bx,by,bz,br);
philpem@5 25620 cimg_forV(*this,k) {
philpem@5 25621 bgrid.fill(0); bgridw.fill(0);
philpem@5 25622 cimg_forXYZ(*this,x,y,z) {
philpem@5 25623 const T val = (*this)(x,y,z,k);
philpem@5 25624 const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
philpem@5 25625 bgrid(X,Y,Z,R) = (float)val;
philpem@5 25626 bgridw(X,Y,Z,R) = 1;
philpem@5 25627 }
philpem@5 25628 bgrid.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
philpem@5 25629 bgridw.blur(nsigmax,nsigmay,nsigmaz,true).deriche(nsigmar,0,'v',false);
philpem@5 25630 if (interpolation_type) cimg_forXYZ(*this,x,y,z) {
philpem@5 25631 const T val = (*this)(x,y,z,k);
philpem@5 25632 const float X = (float)x*bx/width, Y = (float)y*by/height, Z = (float)z*bz/depth, R = (float)((val-m)*br/range),
philpem@5 25633 bval0 = bgrid._linear_atXYZV(X,Y,Z,R), bval1 = bgridw._linear_atXYZV(X,Y,Z,R);
philpem@5 25634 (*this)(x,y,z,k) = (T)(bval0/bval1);
philpem@5 25635 } else cimg_forXYZ(*this,x,y,z) {
philpem@5 25636 const T val = (*this)(x,y,z,k);
philpem@5 25637 const int X = x*bx/width, Y = y*by/height, Z = z*bz/depth, R = (int)((val-m)*br/range);
philpem@5 25638 const float bval0 = bgrid(X,Y,Z,R), bval1 = bgridw(X,Y,Z,R);
philpem@5 25639 (*this)(x,y,z,k) = (T)(bval0/bval1);
philpem@5 25640 }
philpem@5 25641 }
philpem@5 25642 } else { // 2d version of the algorithm
philpem@5 25643 CImg<floatT> bgrid(bx,by,br,2);
philpem@5 25644 cimg_forV(*this,k) {
philpem@5 25645 bgrid.fill(0);
philpem@5 25646 cimg_forXY(*this,x,y) {
philpem@5 25647 const T val = (*this)(x,y,k);
philpem@5 25648 const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
philpem@5 25649 bgrid(X,Y,R,0) = (float)val;
philpem@5 25650 bgrid(X,Y,R,1) = 1;
philpem@5 25651 }
philpem@5 25652 bgrid.blur(nsigmax,nsigmay,0,true).blur(0,0,nsigmar,false);
philpem@5 25653 if (interpolation_type) cimg_forXY(*this,x,y) {
philpem@5 25654 const T val = (*this)(x,y,k);
philpem@5 25655 const float X = (float)x*bx/width, Y = (float)y*by/height, R = (float)((val-m)*br/range),
philpem@5 25656 bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1);
philpem@5 25657 (*this)(x,y,k) = (T)(bval0/bval1);
philpem@5 25658 } else cimg_forXY(*this,x,y) {
philpem@5 25659 const T val = (*this)(x,y,k);
philpem@5 25660 const int X = x*bx/width, Y = y*by/height, R = (int)((val-m)*br/range);
philpem@5 25661 const float bval0 = bgrid(X,Y,R,0), bval1 = bgrid(X,Y,R,1);
philpem@5 25662 (*this)(x,y,k) = (T)(bval0/bval1);
philpem@5 25663 }
philpem@5 25664 }
philpem@5 25665 }
philpem@5 25666 }
philpem@5 25667 return *this;
philpem@5 25668 }
philpem@5 25669
philpem@5 25670 CImg<T> get_blur_bilateral(const float sigmax, const float sigmay, const float sigmaz, const float sigmar,
philpem@5 25671 const int bgridx, const int bgridy, const int bgridz, const int bgridr,
philpem@5 25672 const bool interpolation_type=true) const {
philpem@5 25673 return (+*this).blur_bilateral(sigmax,sigmay,sigmaz,sigmar,bgridx,bgridy,bgridz,bgridr,interpolation_type);
philpem@5 25674 }
philpem@5 25675
philpem@5 25676 //! Blur an image using the bilateral filter.
philpem@5 25677 CImg<T>& blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
philpem@5 25678 const bool interpolation_type=true) {
philpem@5 25679 return blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
philpem@5 25680 }
philpem@5 25681
philpem@5 25682 CImg<T> get_blur_bilateral(const float sigmas, const float sigmar, const int bgrids=-33, const int bgridr=32,
philpem@5 25683 const bool interpolation_type=true) const {
philpem@5 25684 return (+*this).blur_bilateral(sigmas,sigmas,sigmas,sigmar,bgrids,bgrids,bgrids,bgridr,interpolation_type);
philpem@5 25685 }
philpem@5 25686
philpem@5 25687 //! Blur an image in its patch-based space.
philpem@5 25688 CImg<T>& blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
philpem@5 25689 const unsigned int lookup_size=4, const bool fast_approx=true) {
philpem@5 25690
philpem@5 25691 #define _cimg_blur_patch_fastfunc(x) ((x)>3?0:1)
philpem@5 25692 #define _cimg_blur_patch_slowfunc(x) cimg_std::exp(-(x))
philpem@5 25693 #define _cimg_blur_patch3d(N,func) { \
philpem@5 25694 const unsigned int N3 = N*N*N; \
philpem@5 25695 cimg_for##N##XYZ(*this,x,y,z) { \
philpem@5 25696 cimg_plugin_greycstoration_count; \
philpem@5 25697 cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,x,y,z,k,P.ptr(N3*k)); \
philpem@5 25698 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \
philpem@5 25699 float sum_weights = 0; \
philpem@5 25700 cimg_for_in##N##XYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) { \
philpem@5 25701 cimg_forV(*this,k) cimg_get##N##x##N##x##N(*this,p,q,r,k,Q.ptr(N3*k)); \
philpem@5 25702 float distance2 = 0; \
philpem@5 25703 const T *pQ = Q.end(); \
philpem@5 25704 cimg_for(P,pP,T) { const float dI = (float)*pP - (float)*(--pQ); distance2+=dI*dI; } \
philpem@5 25705 distance2/=Pnorm; \
philpem@5 25706 const float dx = (float)p - x, dy = (float)q - y, dz = (float)r - z, \
philpem@5 25707 alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = (float)func(alldist); \
philpem@5 25708 sum_weights+=weight; \
philpem@5 25709 { cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k); } \
philpem@5 25710 } \
philpem@5 25711 if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k)); \
philpem@5 25712 }}
philpem@5 25713 #define _cimg_blur_patch2d(N,func) { \
philpem@5 25714 const unsigned int N2 = N*N; \
philpem@5 25715 cimg_for##N##XY(*this,x,y) { \
philpem@5 25716 cimg_plugin_greycstoration_count; \
philpem@5 25717 cimg_forV(*this,k) cimg_get##N##x##N(*this,x,y,0,k,P.ptr(N2*k)); \
philpem@5 25718 const int x0 = x-rsize1, y0 = y-rsize1, x1 = x+rsize2, y1 = y+rsize2; \
philpem@5 25719 float sum_weights = 0; \
philpem@5 25720 cimg_for_in##N##XY(*this,x0,y0,x1,y1,p,q) { \
philpem@5 25721 cimg_forV(*this,k) cimg_get##N##x##N(*this,p,q,0,k,Q.ptr(N2*k)); \
philpem@5 25722 float distance2 = 0; \
philpem@5 25723 const T *pQ = Q.end(); \
philpem@5 25724 cimg_for(P,pP,T) { const float dI = (float)*pP-(float)*(--pQ); distance2+=dI*dI; } \
philpem@5 25725 distance2/=Pnorm; \
philpem@5 25726 const float dx = (float)p-x, dy = (float)q-y, \
philpem@5 25727 alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = (float)func(alldist); \
philpem@5 25728 sum_weights+=weight; \
philpem@5 25729 { cimg_forV(*this,k) res(x,y,k)+=weight*(*this)(p,q,k); } \
philpem@5 25730 } \
philpem@5 25731 if (sum_weights>0) cimg_forV(*this,k) res(x,y,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,k) = (Tfloat)((*this)(x,y,k)); \
philpem@5 25732 }}
philpem@5 25733
philpem@5 25734 CImg<Tfloat> res(width,height,depth,dim,0);
philpem@5 25735 CImg<T> P(patch_size*patch_size*dim), Q(P);
philpem@5 25736 const float sigma_s2 = sigma_s*sigma_s, sigma_p2 = sigma_p*sigma_p, Pnorm = P.size()*sigma_p2;
philpem@5 25737 const int rsize2 = (int)lookup_size/2, rsize1 = rsize2-1+(lookup_size%2);
philpem@5 25738 if (depth>1) switch (patch_size) { // 3D version
philpem@5 25739 case 2 :
philpem@5 25740 if (fast_approx) { _cimg_blur_patch3d(2,_cimg_blur_patch_fastfunc); }
philpem@5 25741 else { _cimg_blur_patch3d(2,_cimg_blur_patch_slowfunc); }
philpem@5 25742 break;
philpem@5 25743 case 3 :
philpem@5 25744 if (fast_approx) { _cimg_blur_patch3d(3,_cimg_blur_patch_fastfunc); }
philpem@5 25745 else { _cimg_blur_patch3d(3,_cimg_blur_patch_slowfunc); }
philpem@5 25746 break;
philpem@5 25747 default : {
philpem@5 25748 const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
philpem@5 25749 cimg_forXYZ(*this,x,y,z) {
philpem@5 25750 cimg_plugin_greycstoration_count;
philpem@5 25751 P = get_crop(x - psize0,y - psize0,z - psize0,x + psize1,y + psize1,z + psize1,true);
philpem@5 25752 const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2;
philpem@5 25753 float sum_weights = 0;
philpem@5 25754 cimg_for_inXYZ(*this,x0,y0,z0,x1,y1,z1,p,q,r) {
philpem@5 25755 (Q = get_crop(p - psize0,q - psize0,r - psize0,p + psize1,q + psize1,r + psize1,true))-=P;
philpem@5 25756 const float
philpem@5 25757 dx = (float)x - p, dy = (float)y - q, dz = (float)z - r,
philpem@5 25758 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2),
philpem@5 25759 weight = (float)cimg_std::exp(-distance2);
philpem@5 25760 sum_weights+=weight;
philpem@5 25761 cimg_forV(*this,k) res(x,y,z,k)+=weight*(*this)(p,q,r,k);
philpem@5 25762 }
philpem@5 25763 if (sum_weights>0) cimg_forV(*this,k) res(x,y,z,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,z,k) = (Tfloat)((*this)(x,y,z,k));
philpem@5 25764 }
philpem@5 25765 }
philpem@5 25766 } else switch (patch_size) { // 2D version
philpem@5 25767 case 2 :
philpem@5 25768 if (fast_approx) { _cimg_blur_patch2d(2,_cimg_blur_patch_fastfunc); }
philpem@5 25769 else { _cimg_blur_patch2d(2,_cimg_blur_patch_slowfunc); }
philpem@5 25770 break;
philpem@5 25771 case 3 :
philpem@5 25772 if (fast_approx) { _cimg_blur_patch2d(3,_cimg_blur_patch_fastfunc); }
philpem@5 25773 else { _cimg_blur_patch2d(3,_cimg_blur_patch_slowfunc); }
philpem@5 25774 break;
philpem@5 25775 case 4 :
philpem@5 25776 if (fast_approx) { _cimg_blur_patch2d(4,_cimg_blur_patch_fastfunc); }
philpem@5 25777 else { _cimg_blur_patch2d(4,_cimg_blur_patch_slowfunc); }
philpem@5 25778 break;
philpem@5 25779 case 5 :
philpem@5 25780 if (fast_approx) { _cimg_blur_patch2d(5,_cimg_blur_patch_fastfunc); }
philpem@5 25781 else { _cimg_blur_patch2d(5,_cimg_blur_patch_slowfunc); }
philpem@5 25782 break;
philpem@5 25783 case 6 :
philpem@5 25784 if (fast_approx) { _cimg_blur_patch2d(6,_cimg_blur_patch_fastfunc); }
philpem@5 25785 else { _cimg_blur_patch2d(6,_cimg_blur_patch_slowfunc); }
philpem@5 25786 break;
philpem@5 25787 case 7 :
philpem@5 25788 if (fast_approx) { _cimg_blur_patch2d(7,_cimg_blur_patch_fastfunc); }
philpem@5 25789 else { _cimg_blur_patch2d(7,_cimg_blur_patch_slowfunc); }
philpem@5 25790 break;
philpem@5 25791 case 8 :
philpem@5 25792 if (fast_approx) { _cimg_blur_patch2d(8,_cimg_blur_patch_fastfunc); }
philpem@5 25793 else { _cimg_blur_patch2d(8,_cimg_blur_patch_slowfunc); }
philpem@5 25794 break;
philpem@5 25795 case 9 :
philpem@5 25796 if (fast_approx) { _cimg_blur_patch2d(9,_cimg_blur_patch_fastfunc); }
philpem@5 25797 else { _cimg_blur_patch2d(9,_cimg_blur_patch_slowfunc); }
philpem@5 25798 break;
philpem@5 25799 default : {
philpem@5 25800 const int psize1 = (int)patch_size/2, psize0 = psize1-1+(patch_size%2);
philpem@5 25801 cimg_forXY(*this,x,y) {
philpem@5 25802 cimg_plugin_greycstoration_count;
philpem@5 25803 P = get_crop(x - psize0,y - psize0,x + psize1,y + psize1,true);
philpem@5 25804 const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2;
philpem@5 25805 float sum_weights = 0;
philpem@5 25806 cimg_for_inXY(*this,x0,y0,x1,y1,p,q) {
philpem@5 25807 (Q = get_crop(p - psize0,q - psize0,p + psize1,q + psize1,true))-=P;
philpem@5 25808 const float
philpem@5 25809 dx = (float)x - p, dy = (float)y - q,
philpem@5 25810 distance2 = (float)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2),
philpem@5 25811 weight = (float)cimg_std::exp(-distance2);
philpem@5 25812 sum_weights+=weight;
philpem@5 25813 cimg_forV(*this,k) res(x,y,0,k)+=weight*(*this)(p,q,0,k);
philpem@5 25814 }
philpem@5 25815 if (sum_weights>0) cimg_forV(*this,k) res(x,y,0,k)/=sum_weights; else cimg_forV(*this,k) res(x,y,0,k) = (Tfloat)((*this)(x,y,0,k));
philpem@5 25816 }
philpem@5 25817 }
philpem@5 25818 }
philpem@5 25819 return res.transfer_to(*this);
philpem@5 25820 }
philpem@5 25821
philpem@5 25822 CImg<T> get_blur_patch(const unsigned int patch_size, const float sigma_p, const float sigma_s=10,
philpem@5 25823 const unsigned int lookup_size=4, const bool fast_approx=true) const {
philpem@5 25824 return (+*this).blur_patch(patch_size,sigma_p,sigma_s,lookup_size,fast_approx);
philpem@5 25825 }
philpem@5 25826
philpem@5 25827 //! Compute the Fast Fourier Transform of an image (along a specified axis).
philpem@5 25828 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
philpem@5 25829 return CImgList<Tfloat>(*this).FFT(axis,invert);
philpem@5 25830 }
philpem@5 25831
philpem@5 25832 //! Compute the Fast Fourier Transform on an image.
philpem@5 25833 CImgList<Tfloat> get_FFT(const bool invert=false) const {
philpem@5 25834 return CImgList<Tfloat>(*this).FFT(invert);
philpem@5 25835 }
philpem@5 25836
philpem@5 25837 //! Apply a median filter.
philpem@5 25838 CImg<T>& blur_median(const unsigned int n) {
philpem@5 25839 return get_blur_median(n).transfer_to(*this);
philpem@5 25840 }
philpem@5 25841
philpem@5 25842 CImg<T> get_blur_median(const unsigned int n) {
philpem@5 25843 CImg<T> res(width,height,depth,dim);
philpem@5 25844 if (!n || n==1) return *this;
philpem@5 25845 const int hl=n/2, hr=hl-1+n%2;
philpem@5 25846 if (res.depth!=1) { // 3D median filter
philpem@5 25847 CImg<T> vois;
philpem@5 25848 cimg_forXYZV(*this,x,y,z,k) {
philpem@5 25849 const int
philpem@5 25850 x0 = x - hl, y0 = y - hl, z0 = z-hl, x1 = x + hr, y1 = y + hr, z1 = z+hr,
philpem@5 25851 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0,
philpem@5 25852 nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1, nz1 = z1>=dimz()?dimz()-1:z1;
philpem@5 25853 vois = get_crop(nx0,ny0,nz0,k,nx1,ny1,nz1,k);
philpem@5 25854 res(x,y,z,k) = vois.median();
philpem@5 25855 }
philpem@5 25856 } else {
philpem@5 25857 #define _cimg_median_sort(a,b) if ((a)>(b)) cimg::swap(a,b)
philpem@5 25858 if (res.height!=1) switch (n) { // 2D median filter
philpem@5 25859 case 3 : {
philpem@5 25860 T I[9] = { 0 };
philpem@5 25861 CImg_3x3(J,T);
philpem@5 25862 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
philpem@5 25863 cimg_std::memcpy(J,I,9*sizeof(T));
philpem@5 25864 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
philpem@5 25865 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jpn, Jcn);
philpem@5 25866 _cimg_median_sort(Jcp, Jnp); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jcn, Jnn);
philpem@5 25867 _cimg_median_sort(Jpp, Jpc); _cimg_median_sort(Jnc, Jnn); _cimg_median_sort(Jcc, Jcn);
philpem@5 25868 _cimg_median_sort(Jpc, Jpn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jnp, Jnc);
philpem@5 25869 _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcc, Jnp); _cimg_median_sort(Jpn, Jcc);
philpem@5 25870 _cimg_median_sort(Jcc, Jnp);
philpem@5 25871 res(x,y,0,k) = Jcc;
philpem@5 25872 }
philpem@5 25873 } break;
philpem@5 25874 case 5 : {
philpem@5 25875 T I[25] = { 0 };
philpem@5 25876 CImg_5x5(J,T);
philpem@5 25877 cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) {
philpem@5 25878 cimg_std::memcpy(J,I,25*sizeof(T));
philpem@5 25879 _cimg_median_sort(Jbb, Jpb); _cimg_median_sort(Jnb, Jab); _cimg_median_sort(Jcb, Jab); _cimg_median_sort(Jcb, Jnb);
philpem@5 25880 _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbp, Jcp); _cimg_median_sort(Jbp, Jpp); _cimg_median_sort(Jap, Jbc);
philpem@5 25881 _cimg_median_sort(Jnp, Jbc); _cimg_median_sort(Jnp, Jap); _cimg_median_sort(Jcc, Jnc); _cimg_median_sort(Jpc, Jnc);
philpem@5 25882 _cimg_median_sort(Jpc, Jcc); _cimg_median_sort(Jbn, Jpn); _cimg_median_sort(Jac, Jpn); _cimg_median_sort(Jac, Jbn);
philpem@5 25883 _cimg_median_sort(Jnn, Jan); _cimg_median_sort(Jcn, Jan); _cimg_median_sort(Jcn, Jnn); _cimg_median_sort(Jpa, Jca);
philpem@5 25884 _cimg_median_sort(Jba, Jca); _cimg_median_sort(Jba, Jpa); _cimg_median_sort(Jna, Jaa); _cimg_median_sort(Jcb, Jbp);
philpem@5 25885 _cimg_median_sort(Jnb, Jpp); _cimg_median_sort(Jbb, Jpp); _cimg_median_sort(Jbb, Jnb); _cimg_median_sort(Jab, Jcp);
philpem@5 25886 _cimg_median_sort(Jpb, Jcp); _cimg_median_sort(Jpb, Jab); _cimg_median_sort(Jpc, Jac); _cimg_median_sort(Jnp, Jac);
philpem@5 25887 _cimg_median_sort(Jnp, Jpc); _cimg_median_sort(Jcc, Jbn); _cimg_median_sort(Jap, Jbn); _cimg_median_sort(Jap, Jcc);
philpem@5 25888 _cimg_median_sort(Jnc, Jpn); _cimg_median_sort(Jbc, Jpn); _cimg_median_sort(Jbc, Jnc); _cimg_median_sort(Jba, Jna);
philpem@5 25889 _cimg_median_sort(Jcn, Jna); _cimg_median_sort(Jcn, Jba); _cimg_median_sort(Jpa, Jaa); _cimg_median_sort(Jnn, Jaa);
philpem@5 25890 _cimg_median_sort(Jnn, Jpa); _cimg_median_sort(Jan, Jca); _cimg_median_sort(Jnp, Jcn); _cimg_median_sort(Jap, Jnn);
philpem@5 25891 _cimg_median_sort(Jbb, Jnn); _cimg_median_sort(Jbb, Jap); _cimg_median_sort(Jbc, Jan); _cimg_median_sort(Jpb, Jan);
philpem@5 25892 _cimg_median_sort(Jpb, Jbc); _cimg_median_sort(Jpc, Jba); _cimg_median_sort(Jcb, Jba); _cimg_median_sort(Jcb, Jpc);
philpem@5 25893 _cimg_median_sort(Jcc, Jpa); _cimg_median_sort(Jnb, Jpa); _cimg_median_sort(Jnb, Jcc); _cimg_median_sort(Jnc, Jca);
philpem@5 25894 _cimg_median_sort(Jab, Jca); _cimg_median_sort(Jab, Jnc); _cimg_median_sort(Jac, Jna); _cimg_median_sort(Jbp, Jna);
philpem@5 25895 _cimg_median_sort(Jbp, Jac); _cimg_median_sort(Jbn, Jaa); _cimg_median_sort(Jpp, Jaa); _cimg_median_sort(Jpp, Jbn);
philpem@5 25896 _cimg_median_sort(Jcp, Jpn); _cimg_median_sort(Jcp, Jan); _cimg_median_sort(Jnc, Jpa); _cimg_median_sort(Jbn, Jna);
philpem@5 25897 _cimg_median_sort(Jcp, Jnc); _cimg_median_sort(Jcp, Jbn); _cimg_median_sort(Jpb, Jap); _cimg_median_sort(Jnb, Jpc);
philpem@5 25898 _cimg_median_sort(Jbp, Jcn); _cimg_median_sort(Jpc, Jcn); _cimg_median_sort(Jap, Jcn); _cimg_median_sort(Jab, Jbc);
philpem@5 25899 _cimg_median_sort(Jpp, Jcc); _cimg_median_sort(Jcp, Jac); _cimg_median_sort(Jab, Jpp); _cimg_median_sort(Jab, Jcp);
philpem@5 25900 _cimg_median_sort(Jcc, Jac); _cimg_median_sort(Jbc, Jac); _cimg_median_sort(Jpp, Jcp); _cimg_median_sort(Jbc, Jcc);
philpem@5 25901 _cimg_median_sort(Jpp, Jbc); _cimg_median_sort(Jpp, Jcn); _cimg_median_sort(Jcc, Jcn); _cimg_median_sort(Jcp, Jcn);
philpem@5 25902 _cimg_median_sort(Jcp, Jbc); _cimg_median_sort(Jcc, Jnn); _cimg_median_sort(Jcp, Jcc); _cimg_median_sort(Jbc, Jnn);
philpem@5 25903 _cimg_median_sort(Jcc, Jba); _cimg_median_sort(Jbc, Jba); _cimg_median_sort(Jbc, Jcc);
philpem@5 25904 res(x,y,0,k) = Jcc;
philpem@5 25905 }
philpem@5 25906 } break;
philpem@5 25907 default : {
philpem@5 25908 CImg<T> vois;
philpem@5 25909 cimg_forXYV(*this,x,y,k) {
philpem@5 25910 const int
philpem@5 25911 x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr,
philpem@5 25912 nx0 = x0<0?0:x0, ny0 = y0<0?0:y0,
philpem@5 25913 nx1 = x1>=dimx()?dimx()-1:x1, ny1 = y1>=dimy()?dimy()-1:y1;
philpem@5 25914 vois = get_crop(nx0,ny0,0,k,nx1,ny1,0,k);
philpem@5 25915 res(x,y,0,k) = vois.median();
philpem@5 25916 }
philpem@5 25917 }
philpem@5 25918 } else switch (n) { // 1D median filter
philpem@5 25919 case 2 : {
philpem@5 25920 T I[4] = { 0 };
philpem@5 25921 cimg_forV(*this,k) cimg_for2x2(*this,x,y,0,k,I) res(x,0,0,k) = (T)(0.5f*(I[0]+I[1]));
philpem@5 25922 } break;
philpem@5 25923 case 3 : {
philpem@5 25924 T I[9] = { 0 };
philpem@5 25925 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
philpem@5 25926 res(x,0,0,k) = I[3]<I[4]?
philpem@5 25927 (I[4]<I[5]?I[4]:
philpem@5 25928 (I[3]<I[5]?I[5]:I[3])):
philpem@5 25929 (I[3]<I[5]?I[3]:
philpem@5 25930 (I[4]<I[5]?I[5]:I[4]));
philpem@5 25931 }
philpem@5 25932 } break;
philpem@5 25933 default : {
philpem@5 25934 CImg<T> vois;
philpem@5 25935 cimg_forXV(*this,x,k) {
philpem@5 25936 const int
philpem@5 25937 x0 = x - hl, x1 = x + hr,
philpem@5 25938 nx0 = x0<0?0:x0, nx1 = x1>=dimx()?dimx()-1:x1;
philpem@5 25939 vois = get_crop(nx0,0,0,k,nx1,0,0,k);
philpem@5 25940 res(x,0,0,k) = vois.median();
philpem@5 25941 }
philpem@5 25942 }
philpem@5 25943 }
philpem@5 25944 }
philpem@5 25945 return res;
philpem@5 25946 }
philpem@5 25947
philpem@5 25948 //! Sharpen image using anisotropic shock filters or inverse diffusion.
philpem@5 25949 CImg<T>& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) {
philpem@5 25950 if (is_empty()) return *this;
philpem@5 25951 T valm, valM = maxmin(valm);
philpem@5 25952 const bool threed = (depth>1);
philpem@5 25953 const float nedge = 0.5f*edge;
philpem@5 25954 CImg<Tfloat> val, vec, veloc(width,height,depth,dim);
philpem@5 25955
philpem@5 25956 if (threed) {
philpem@5 25957 CImg_3x3x3(I,T);
philpem@5 25958 if (sharpen_type) { // 3D Shock filter.
philpem@5 25959 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
philpem@5 25960 if (sigma>0) G.blur(sigma);
philpem@5 25961
philpem@5 25962 cimg_forXYZ(G,x,y,z) {
philpem@5 25963 G.get_tensor_at(x,y,z).symmetric_eigen(val,vec);
philpem@5 25964 G(x,y,z,0) = vec(0,0);
philpem@5 25965 G(x,y,z,1) = vec(0,1);
philpem@5 25966 G(x,y,z,2) = vec(0,2);
philpem@5 25967 G(x,y,z,3) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1]+val[2],-(Tfloat)nedge);
philpem@5 25968 }
philpem@5 25969 cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) {
philpem@5 25970 const Tfloat
philpem@5 25971 u = G(x,y,z,0),
philpem@5 25972 v = G(x,y,z,1),
philpem@5 25973 w = G(x,y,z,2),
philpem@5 25974 amp = G(x,y,z,3),
philpem@5 25975 ixx = (Tfloat)Incc + Ipcc - 2*Iccc,
philpem@5 25976 ixy = 0.25f*((Tfloat)Innc + Ippc - Inpc - Ipnc),
philpem@5 25977 ixz = 0.25f*((Tfloat)Incn + Ipcp - Incp - Ipcn),
philpem@5 25978 iyy = (Tfloat)Icnc + Icpc - 2*Iccc,
philpem@5 25979 iyz = 0.25f*((Tfloat)Icnn + Icpp - Icnp - Icpn),
philpem@5 25980 izz = (Tfloat)Iccn + Iccp - 2*Iccc,
philpem@5 25981 ixf = (Tfloat)Incc - Iccc,
philpem@5 25982 ixb = (Tfloat)Iccc - Ipcc,
philpem@5 25983 iyf = (Tfloat)Icnc - Iccc,
philpem@5 25984 iyb = (Tfloat)Iccc - Icpc,
philpem@5 25985 izf = (Tfloat)Iccn - Iccc,
philpem@5 25986 izb = (Tfloat)Iccc - Iccp,
philpem@5 25987 itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz,
philpem@5 25988 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb);
philpem@5 25989 veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it);
philpem@5 25990 }
philpem@5 25991 } else cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) veloc(x,y,z,k) = -(Tfloat)Ipcc-Incc-Icpc-Icnc-Iccp-Iccn+6*Iccc; // 3D Inverse diffusion.
philpem@5 25992 } else {
philpem@5 25993 CImg_3x3(I,T);
philpem@5 25994 if (sharpen_type) { // 2D Shock filter.
philpem@5 25995 CImg<Tfloat> G = (alpha>0?get_blur(alpha).get_structure_tensor():get_structure_tensor());
philpem@5 25996 if (sigma>0) G.blur(sigma);
philpem@5 25997 cimg_forXY(G,x,y) {
philpem@5 25998 G.get_tensor_at(x,y).symmetric_eigen(val,vec);
philpem@5 25999 G(x,y,0) = vec(0,0);
philpem@5 26000 G(x,y,1) = vec(0,1);
philpem@5 26001 G(x,y,2) = 1 - (Tfloat)cimg_std::pow(1+val[0]+val[1],-(Tfloat)nedge);
philpem@5 26002 }
philpem@5 26003 cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) {
philpem@5 26004 const Tfloat
philpem@5 26005 u = G(x,y,0),
philpem@5 26006 v = G(x,y,1),
philpem@5 26007 amp = G(x,y,2),
philpem@5 26008 ixx = (Tfloat)Inc + Ipc - 2*Icc,
philpem@5 26009 ixy = 0.25f*((Tfloat)Inn + Ipp - Inp - Ipn),
philpem@5 26010 iyy = (Tfloat)Icn + Icp - 2*Icc,
philpem@5 26011 ixf = (Tfloat)Inc - Icc,
philpem@5 26012 ixb = (Tfloat)Icc - Ipc,
philpem@5 26013 iyf = (Tfloat)Icn - Icc,
philpem@5 26014 iyb = (Tfloat)Icc - Icp,
philpem@5 26015 itt = u*u*ixx + v*v*iyy + 2*u*v*ixy,
philpem@5 26016 it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb);
philpem@5 26017 veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it);
philpem@5 26018 }
philpem@5 26019 } else cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) veloc(x,y,k) = -(Tfloat)Ipc-Inc-Icp-Icn+4*Icc; // 3D Inverse diffusion.
philpem@5 26020 }
philpem@5 26021 float m, M = (float)veloc.maxmin(m);
philpem@5 26022 const float vmax = (float)cimg::max(cimg::abs(m),cimg::abs(M));
philpem@5 26023 if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; }
philpem@5 26024 return cut(valm,valM);
philpem@5 26025 }
philpem@5 26026
philpem@5 26027 CImg<T> get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, const float alpha=0, const float sigma=0) const {
philpem@5 26028 return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma);
philpem@5 26029 }
philpem@5 26030
philpem@5 26031 //! Compute the Haar multiscale wavelet transform (monodimensional version).
philpem@5 26032 /**
philpem@5 26033 \param axis Axis considered for the transform.
philpem@5 26034 \param invert Set inverse of direct transform.
philpem@5 26035 \param nb_scales Number of scales used for the transform.
philpem@5 26036 **/
philpem@5 26037 CImg<T>& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) {
philpem@5 26038 return get_haar(axis,invert,nb_scales).transfer_to(*this);
philpem@5 26039 }
philpem@5 26040
philpem@5 26041 CImg<Tfloat> get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const {
philpem@5 26042 if (is_empty() || !nb_scales) return *this;
philpem@5 26043 CImg<Tfloat> res;
philpem@5 26044
philpem@5 26045 if (nb_scales==1) {
philpem@5 26046 switch (cimg::uncase(axis)) { // Single scale transform
philpem@5 26047 case 'x' : {
philpem@5 26048 const unsigned int w = width/2;
philpem@5 26049 if (w) {
philpem@5 26050 if (w%2)
philpem@5 26051 throw CImgInstanceException("CImg<%s>::haar() : Sub-image width = %u is not even at a particular scale (=%u).",
philpem@5 26052 pixel_type(),w);
philpem@5 26053 res.assign(width,height,depth,dim);
philpem@5 26054 if (invert) cimg_forYZV(*this,y,z,v) { // Inverse transform along X
philpem@5 26055 for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
philpem@5 26056 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(xw,y,z,v);
philpem@5 26057 res(x2++,y,z,v) = val0 - val1;
philpem@5 26058 res(x2++,y,z,v) = val0 + val1;
philpem@5 26059 }
philpem@5 26060 } else cimg_forYZV(*this,y,z,v) { // Direct transform along X
philpem@5 26061 for (unsigned int x=0, xw=w, x2=0; x<w; ++x, ++xw) {
philpem@5 26062 const Tfloat val0 = (Tfloat)(*this)(x2++,y,z,v), val1 = (Tfloat)(*this)(x2++,y,z,v);
philpem@5 26063 res(x,y,z,v) = (val0 + val1)/2;
philpem@5 26064 res(xw,y,z,v) = (val1 - val0)/2;
philpem@5 26065 }
philpem@5 26066 }
philpem@5 26067 } else return *this;
philpem@5 26068 } break;
philpem@5 26069 case 'y' : {
philpem@5 26070 const unsigned int h = height/2;
philpem@5 26071 if (h) {
philpem@5 26072 if (h%2)
philpem@5 26073 throw CImgInstanceException("CImg<%s>::haar() : Sub-image height = %u is not even at a particular scale.",
philpem@5 26074 pixel_type(),h);
philpem@5 26075 res.assign(width,height,depth,dim);
philpem@5 26076 if (invert) cimg_forXZV(*this,x,z,v) { // Inverse transform along Y
philpem@5 26077 for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) {
philpem@5 26078 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,yh,z,v);
philpem@5 26079 res(x,y2++,z,v) = val0 - val1;
philpem@5 26080 res(x,y2++,z,v) = val0 + val1;
philpem@5 26081 }
philpem@5 26082 } else cimg_forXZV(*this,x,z,v) {
philpem@5 26083 for (unsigned int y=0, yh=h, y2=0; y<h; ++y, ++yh) { // Direct transform along Y
philpem@5 26084 const Tfloat val0 = (Tfloat)(*this)(x,y2++,z,v), val1 = (Tfloat)(*this)(x,y2++,z,v);
philpem@5 26085 res(x,y,z,v) = (val0 + val1)/2;
philpem@5 26086 res(x,yh,z,v) = (val1 - val0)/2;
philpem@5 26087 }
philpem@5 26088 }
philpem@5 26089 } else return *this;
philpem@5 26090 } break;
philpem@5 26091 case 'z' : {
philpem@5 26092 const unsigned int d = depth/2;
philpem@5 26093 if (d) {
philpem@5 26094 if (d%2)
philpem@5 26095 throw CImgInstanceException("CImg<%s>::haar() : Sub-image depth = %u is not even at a particular scale.",
philpem@5 26096 pixel_type(),d);
philpem@5 26097 res.assign(width,height,depth,dim);
philpem@5 26098 if (invert) cimg_forXYV(*this,x,y,v) { // Inverse transform along Z
philpem@5 26099 for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) {
philpem@5 26100 const Tfloat val0 = (Tfloat)(*this)(x,y,z,v), val1 = (Tfloat)(*this)(x,y,zd,v);
philpem@5 26101 res(x,y,z2++,v) = val0 - val1;
philpem@5 26102 res(x,y,z2++,v) = val0 + val1;
philpem@5 26103 }
philpem@5 26104 } else cimg_forXYV(*this,x,y,v) {
philpem@5 26105 for (unsigned int z=0, zd=d, z2=0; z<d; ++z, ++zd) { // Direct transform along Z
philpem@5 26106 const Tfloat val0 = (Tfloat)(*this)(x,y,z2++,v), val1 = (Tfloat)(*this)(x,y,z2++,v);
philpem@5 26107 res(x,y,z,v) = (val0 + val1)/2;
philpem@5 26108 res(x,y,zd,v) = (val1 - val0)/2;
philpem@5 26109 }
philpem@5 26110 }
philpem@5 26111 } else return *this;
philpem@5 26112 } break;
philpem@5 26113 default :
philpem@5 26114 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
philpem@5 26115 pixel_type(),axis);
philpem@5 26116 }
philpem@5 26117 } else { // Multi-scale version
philpem@5 26118 if (invert) {
philpem@5 26119 res.assign(*this);
philpem@5 26120 switch (cimg::uncase(axis)) {
philpem@5 26121 case 'x' : {
philpem@5 26122 unsigned int w = width;
philpem@5 26123 for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
philpem@5 26124 for (w=w?w:1; w<=width; w*=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',true,1));
philpem@5 26125 } break;
philpem@5 26126 case 'y' : {
philpem@5 26127 unsigned int h = width;
philpem@5 26128 for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
philpem@5 26129 for (h=h?h:1; h<=height; h*=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',true,1));
philpem@5 26130 } break;
philpem@5 26131 case 'z' : {
philpem@5 26132 unsigned int d = depth;
philpem@5 26133 for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
philpem@5 26134 for (d=d?d:1; d<=depth; d*=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',true,1));
philpem@5 26135 } break;
philpem@5 26136 default :
philpem@5 26137 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
philpem@5 26138 pixel_type(),axis);
philpem@5 26139 }
philpem@5 26140 } else { // Direct transform
philpem@5 26141 res = get_haar(axis,false,1);
philpem@5 26142 switch (cimg::uncase(axis)) {
philpem@5 26143 case 'x' : {
philpem@5 26144 for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2) res.draw_image(res.get_crop(0,w-1).get_haar('x',false,1));
philpem@5 26145 } break;
philpem@5 26146 case 'y' : {
philpem@5 26147 for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2) res.draw_image(res.get_crop(0,0,width-1,h-1).get_haar('y',false,1));
philpem@5 26148 } break;
philpem@5 26149 case 'z' : {
philpem@5 26150 for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2) res.draw_image(res.get_crop(0,0,0,width-1,height-1,d-1).get_haar('z',false,1));
philpem@5 26151 } break;
philpem@5 26152 default :
philpem@5 26153 throw CImgArgumentException("CImg<%s>::haar() : Invalid axis '%c', must be 'x','y' or 'z'.",
philpem@5 26154 pixel_type(),axis);
philpem@5 26155 }
philpem@5 26156 }
philpem@5 26157 }
philpem@5 26158 return res;
philpem@5 26159 }
philpem@5 26160
philpem@5 26161 //! Compute the Haar multiscale wavelet transform.
philpem@5 26162 /**
philpem@5 26163 \param invert Set inverse of direct transform.
philpem@5 26164 \param nb_scales Number of scales used for the transform.
philpem@5 26165 **/
philpem@5 26166 CImg<T>& haar(const bool invert=false, const unsigned int nb_scales=1) {
philpem@5 26167 return get_haar(invert,nb_scales).transfer_to(*this);
philpem@5 26168 }
philpem@5 26169
philpem@5 26170 CImg<Tfloat> get_haar(const bool invert=false, const unsigned int nb_scales=1) const {
philpem@5 26171 CImg<Tfloat> res;
philpem@5 26172
philpem@5 26173 if (nb_scales==1) { // Single scale transform
philpem@5 26174 if (width>1) get_haar('x',invert,1).transfer_to(res);
philpem@5 26175 if (height>1) { if (res) res.get_haar('y',invert,1).transfer_to(res); else get_haar('y',invert,1).transfer_to(res); }
philpem@5 26176 if (depth>1) { if (res) res.get_haar('z',invert,1).transfer_to(res); else get_haar('z',invert,1).transfer_to(res); }
philpem@5 26177 if (res) return res;
philpem@5 26178 } else { // Multi-scale transform
philpem@5 26179 if (invert) { // Inverse transform
philpem@5 26180 res.assign(*this);
philpem@5 26181 if (width>1) {
philpem@5 26182 if (height>1) {
philpem@5 26183 if (depth>1) {
philpem@5 26184 unsigned int w = width, h = height, d = depth; for (unsigned int s=1; w && h && d && s<nb_scales; ++s) { w/=2; h/=2; d/=2; }
philpem@5 26185 for (w=w?w:1, h=h?h:1, d=d?d:1; w<=width && h<=height && d<=depth; w*=2, h*=2, d*=2)
philpem@5 26186 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).get_haar(true,1));
philpem@5 26187 } else {
philpem@5 26188 unsigned int w = width, h = height; for (unsigned int s=1; w && h && s<nb_scales; ++s) { w/=2; h/=2; }
philpem@5 26189 for (w=w?w:1, h=h?h:1; w<=width && h<=height; w*=2, h*=2)
philpem@5 26190 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).get_haar(true,1));
philpem@5 26191 }
philpem@5 26192 } else {
philpem@5 26193 if (depth>1) {
philpem@5 26194 unsigned int w = width, d = depth; for (unsigned int s=1; w && d && s<nb_scales; ++s) { w/=2; d/=2; }
philpem@5 26195 for (w=w?w:1, d=d?d:1; w<=width && d<=depth; w*=2, d*=2)
philpem@5 26196 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).get_haar(true,1));
philpem@5 26197 } else {
philpem@5 26198 unsigned int w = width; for (unsigned int s=1; w && s<nb_scales; ++s) w/=2;
philpem@5 26199 for (w=w?w:1; w<=width; w*=2)
philpem@5 26200 res.draw_image(res.get_crop(0,0,0,w-1,0,0).get_haar(true,1));
philpem@5 26201 }
philpem@5 26202 }
philpem@5 26203 } else {
philpem@5 26204 if (height>1) {
philpem@5 26205 if (depth>1) {
philpem@5 26206 unsigned int h = height, d = depth; for (unsigned int s=1; h && d && s<nb_scales; ++s) { h/=2; d/=2; }
philpem@5 26207 for (h=h?h:1, d=d?d:1; h<=height && d<=depth; h*=2, d*=2)
philpem@5 26208 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).get_haar(true,1));
philpem@5 26209 } else {
philpem@5 26210 unsigned int h = height; for (unsigned int s=1; h && s<nb_scales; ++s) h/=2;
philpem@5 26211 for (h=h?h:1; h<=height; h*=2)
philpem@5 26212 res.draw_image(res.get_crop(0,0,0,0,h-1,0).get_haar(true,1));
philpem@5 26213 }
philpem@5 26214 } else {
philpem@5 26215 if (depth>1) {
philpem@5 26216 unsigned int d = depth; for (unsigned int s=1; d && s<nb_scales; ++s) d/=2;
philpem@5 26217 for (d=d?d:1; d<=depth; d*=2)
philpem@5 26218 res.draw_image(res.get_crop(0,0,0,0,0,d-1).get_haar(true,1));
philpem@5 26219 } else return *this;
philpem@5 26220 }
philpem@5 26221 }
philpem@5 26222 } else { // Direct transform
philpem@5 26223 res = get_haar(false,1);
philpem@5 26224 if (width>1) {
philpem@5 26225 if (height>1) {
philpem@5 26226 if (depth>1) for (unsigned int s=1, w=width/2, h=height/2, d=depth/2; w && h && d && s<nb_scales; ++s, w/=2, h/=2, d/=2)
philpem@5 26227 res.draw_image(res.get_crop(0,0,0,w-1,h-1,d-1).haar(false,1));
philpem@5 26228 else for (unsigned int s=1, w=width/2, h=height/2; w && h && s<nb_scales; ++s, w/=2, h/=2)
philpem@5 26229 res.draw_image(res.get_crop(0,0,0,w-1,h-1,0).haar(false,1));
philpem@5 26230 } else {
philpem@5 26231 if (depth>1) for (unsigned int s=1, w=width/2, d=depth/2; w && d && s<nb_scales; ++s, w/=2, d/=2)
philpem@5 26232 res.draw_image(res.get_crop(0,0,0,w-1,0,d-1).haar(false,1));
philpem@5 26233 else for (unsigned int s=1, w=width/2; w && s<nb_scales; ++s, w/=2)
philpem@5 26234 res.draw_image(res.get_crop(0,0,0,w-1,0,0).haar(false,1));
philpem@5 26235 }
philpem@5 26236 } else {
philpem@5 26237 if (height>1) {
philpem@5 26238 if (depth>1) for (unsigned int s=1, h=height/2, d=depth/2; h && d && s<nb_scales; ++s, h/=2, d/=2)
philpem@5 26239 res.draw_image(res.get_crop(0,0,0,0,h-1,d-1).haar(false,1));
philpem@5 26240 else for (unsigned int s=1, h=height/2; h && s<nb_scales; ++s, h/=2)
philpem@5 26241 res.draw_image(res.get_crop(0,0,0,0,h-1,0).haar(false,1));
philpem@5 26242 } else {
philpem@5 26243 if (depth>1) for (unsigned int s=1, d=depth/2; d && s<nb_scales; ++s, d/=2)
philpem@5 26244 res.draw_image(res.get_crop(0,0,0,0,0,d-1).haar(false,1));
philpem@5 26245 else return *this;
philpem@5 26246 }
philpem@5 26247 }
philpem@5 26248 }
philpem@5 26249 return res;
philpem@5 26250 }
philpem@5 26251 return *this;
philpem@5 26252 }
philpem@5 26253
philpem@5 26254 //! Estimate a displacement field between instance image and given target image.
philpem@5 26255 CImg<T>& displacement_field(const CImg<T>& target, const float smooth=0.1f, const float precision=0.1f,
philpem@5 26256 const unsigned int nb_scales=0, const unsigned int itermax=10000) {
philpem@5 26257 return get_displacement_field(target,smooth,precision,nb_scales,itermax).transfer_to(*this);
philpem@5 26258 }
philpem@5 26259
philpem@5 26260 CImg<Tfloat> get_displacement_field(const CImg<T>& target,
philpem@5 26261 const float smoothness=0.1f, const float precision=0.1f,
philpem@5 26262 const unsigned int nb_scales=0, const unsigned int itermax=10000) const {
philpem@5 26263 if (is_empty() || !target) return *this;
philpem@5 26264 if (!is_sameXYZV(target))
philpem@5 26265 throw CImgArgumentException("CImg<%s>::displacement_field() : Instance image (%u,%u,%u,%u,%p) and target image (%u,%u,%u,%u,%p) "
philpem@5 26266 "have different size.",
philpem@5 26267 pixel_type(),width,height,depth,dim,data,
philpem@5 26268 target.width,target.height,target.depth,target.dim,target.data);
philpem@5 26269 if (smoothness<0)
philpem@5 26270 throw CImgArgumentException("CImg<%s>::displacement_field() : Smoothness parameter %g is negative.",
philpem@5 26271 pixel_type(),smoothness);
philpem@5 26272 if (precision<0)
philpem@5 26273 throw CImgArgumentException("CImg<%s>::displacement_field() : Precision parameter %g is negative.",
philpem@5 26274 pixel_type(),precision);
philpem@5 26275
philpem@5 26276 const unsigned int nscales = nb_scales>0?nb_scales:(unsigned int)(2*cimg_std::log((double)(cimg::max(width,height,depth))));
philpem@5 26277 Tfloat m1, M1 = (Tfloat)maxmin(m1), m2, M2 = (Tfloat)target.maxmin(m2);
philpem@5 26278 const Tfloat factor = cimg::max(cimg::abs(m1),cimg::abs(M1),cimg::abs(m2),cimg::abs(M2));
philpem@5 26279 CImg<Tfloat> U0;
philpem@5 26280 const bool threed = (depth>1);
philpem@5 26281
philpem@5 26282 // Begin multi-scale motion estimation
philpem@5 26283 for (int scale = (int)nscales-1; scale>=0; --scale) {
philpem@5 26284 const float sfactor = (float)cimg_std::pow(1.5f,(float)scale), sprecision = (float)(precision/cimg_std::pow(2.25,1+scale));
philpem@5 26285 const int
philpem@5 26286 sw = (int)(width/sfactor), sh = (int)(height/sfactor), sd = (int)(depth/sfactor),
philpem@5 26287 swidth = sw?sw:1, sheight = sh?sh:1, sdepth = sd?sd:1;
philpem@5 26288 CImg<Tfloat>
philpem@5 26289 I1 = get_resize(swidth,sheight,sdepth,-100,2),
philpem@5 26290 I2 = target.get_resize(swidth,sheight,sdepth,-100,2);
philpem@5 26291 I1/=factor; I2/=factor;
philpem@5 26292 CImg<Tfloat> U;
philpem@5 26293 if (U0) U = (U0*=1.5f).get_resize(I1.dimx(),I1.dimy(),I1.dimz(),-100,3);
philpem@5 26294 else U.assign(I1.dimx(),I1.dimy(),I1.dimz(),threed?3:2,0);
philpem@5 26295
philpem@5 26296 // Begin single-scale motion estimation
philpem@5 26297 CImg<Tfloat> veloc(U);
philpem@5 26298 float dt = 2, Energy = cimg::type<float>::max();
philpem@5 26299 const CImgList<Tfloat> dI = I2.get_gradient();
philpem@5 26300 for (unsigned int iter=0; iter<itermax; iter++) {
philpem@5 26301 veloc.fill(0);
philpem@5 26302 float nEnergy = 0;
philpem@5 26303 if (threed) {
philpem@5 26304 cimg_for3XYZ(U,x,y,z) {
philpem@5 26305 const float X = (float)(x + U(x,y,z,0)), Y = (float)(y + U(x,y,z,1)), Z = (float)(z + U(x,y,z,2));
philpem@5 26306 cimg_forV(U,k) {
philpem@5 26307 const Tfloat
philpem@5 26308 Ux = 0.5f*(U(_n1x,y,z,k) - U(_p1x,y,z,k)),
philpem@5 26309 Uy = 0.5f*(U(x,_n1y,z,k) - U(x,_p1y,z,k)),
philpem@5 26310 Uz = 0.5f*(U(x,y,_n1z,k) - U(x,y,_p1z,k)),
philpem@5 26311 Uxx = U(_n1x,y,z,k) + U(_p1x,y,z,k) - 2*U(x,y,z,k),
philpem@5 26312 Uyy = U(x,_n1y,z,k) + U(x,_p1y,z,k) - 2*U(x,y,z,k),
philpem@5 26313 Uzz = U(x,y,_n1z,k) + U(x,y,_n1z,k) - 2*U(x,y,z,k);
philpem@5 26314 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy + Uz*Uz));
philpem@5 26315 Tfloat deltaIgrad = 0;
philpem@5 26316 cimg_forV(I1,i) {
philpem@5 26317 const Tfloat deltaIi = (float)(I2._linear_atXYZ(X,Y,Z,i) - I1(x,y,z,i));
philpem@5 26318 nEnergy += (float)(deltaIi*deltaIi/2);
philpem@5 26319 deltaIgrad+=-deltaIi*dI[k]._linear_atXYZ(X,Y,Z,i);
philpem@5 26320 }
philpem@5 26321 veloc(x,y,z,k) = deltaIgrad + smoothness*(Uxx + Uyy + Uzz);
philpem@5 26322 }
philpem@5 26323 }
philpem@5 26324 } else {
philpem@5 26325 cimg_for3XY(U,x,y) {
philpem@5 26326 const float X = (float)(x + U(x,y,0)), Y = (float)(y + U(x,y,1));
philpem@5 26327 cimg_forV(U,k) {
philpem@5 26328 const Tfloat
philpem@5 26329 Ux = 0.5f*(U(_n1x,y,k) - U(_p1x,y,k)),
philpem@5 26330 Uy = 0.5f*(U(x,_n1y,k) - U(x,_p1y,k)),
philpem@5 26331 Uxx = U(_n1x,y,k) + U(_p1x,y,k) - 2*U(x,y,k),
philpem@5 26332 Uyy = U(x,_n1y,k) + U(x,_p1y,k) - 2*U(x,y,k);
philpem@5 26333 nEnergy += (float)(smoothness*(Ux*Ux + Uy*Uy));
philpem@5 26334 Tfloat deltaIgrad = 0;
philpem@5 26335 cimg_forV(I1,i) {
philpem@5 26336 const Tfloat deltaIi = (float)(I2._linear_atXY(X,Y,i) - I1(x,y,i));
philpem@5 26337 nEnergy += (float)(deltaIi*deltaIi/2);
philpem@5 26338 deltaIgrad+=-deltaIi*dI[k]._linear_atXY(X,Y,i);
philpem@5 26339 }
philpem@5 26340 veloc(x,y,k) = deltaIgrad + smoothness*(Uxx + Uyy);
philpem@5 26341 }
philpem@5 26342 }
philpem@5 26343 }
philpem@5 26344 const Tfloat vmax = cimg::max(cimg::abs(veloc.min()), cimg::abs(veloc.max()));
philpem@5 26345 U+=(veloc*=dt/vmax);
philpem@5 26346 if (cimg::abs(nEnergy-Energy)<sprecision) break;
philpem@5 26347 if (nEnergy<Energy) dt*=0.5f;
philpem@5 26348 Energy = nEnergy;
philpem@5 26349 }
philpem@5 26350 U.transfer_to(U0);
philpem@5 26351 }
philpem@5 26352 return U0;
philpem@5 26353 }
philpem@5 26354
philpem@5 26355 //@}
philpem@5 26356 //-----------------------------
philpem@5 26357 //
philpem@5 26358 //! \name Matrix and Vectors
philpem@5 26359 //@{
philpem@5 26360 //-----------------------------
philpem@5 26361
philpem@5 26362 //! Return a vector with specified coefficients.
philpem@5 26363 static CImg<T> vector(const T& a0) {
philpem@5 26364 static CImg<T> r(1,1); r[0] = a0;
philpem@5 26365 return r;
philpem@5 26366 }
philpem@5 26367
philpem@5 26368 //! Return a vector with specified coefficients.
philpem@5 26369 static CImg<T> vector(const T& a0, const T& a1) {
philpem@5 26370 static CImg<T> r(1,2); T *ptr = r.data;
philpem@5 26371 *(ptr++) = a0; *(ptr++) = a1;
philpem@5 26372 return r;
philpem@5 26373 }
philpem@5 26374
philpem@5 26375 //! Return a vector with specified coefficients.
philpem@5 26376 static CImg<T> vector(const T& a0, const T& a1, const T& a2) {
philpem@5 26377 static CImg<T> r(1,3); T *ptr = r.data;
philpem@5 26378 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
philpem@5 26379 return r;
philpem@5 26380 }
philpem@5 26381
philpem@5 26382 //! Return a vector with specified coefficients.
philpem@5 26383 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3) {
philpem@5 26384 static CImg<T> r(1,4); T *ptr = r.data;
philpem@5 26385 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26386 return r;
philpem@5 26387 }
philpem@5 26388
philpem@5 26389 //! Return a vector with specified coefficients.
philpem@5 26390 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
philpem@5 26391 static CImg<T> r(1,5); T *ptr = r.data;
philpem@5 26392 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
philpem@5 26393 return r;
philpem@5 26394 }
philpem@5 26395
philpem@5 26396 //! Return a vector with specified coefficients.
philpem@5 26397 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) {
philpem@5 26398 static CImg<T> r(1,6); T *ptr = r.data;
philpem@5 26399 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
philpem@5 26400 return r;
philpem@5 26401 }
philpem@5 26402
philpem@5 26403 //! Return a vector with specified coefficients.
philpem@5 26404 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26405 const T& a4, const T& a5, const T& a6) {
philpem@5 26406 static CImg<T> r(1,7); T *ptr = r.data;
philpem@5 26407 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26408 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6;
philpem@5 26409 return r;
philpem@5 26410 }
philpem@5 26411
philpem@5 26412 //! Return a vector with specified coefficients.
philpem@5 26413 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26414 const T& a4, const T& a5, const T& a6, const T& a7) {
philpem@5 26415 static CImg<T> r(1,8); T *ptr = r.data;
philpem@5 26416 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26417 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26418 return r;
philpem@5 26419 }
philpem@5 26420
philpem@5 26421 //! Return a vector with specified coefficients.
philpem@5 26422 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26423 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26424 const T& a8) {
philpem@5 26425 static CImg<T> r(1,9); T *ptr = r.data;
philpem@5 26426 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26427 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26428 *(ptr++) = a8;
philpem@5 26429 return r;
philpem@5 26430 }
philpem@5 26431
philpem@5 26432 //! Return a vector with specified coefficients.
philpem@5 26433 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26434 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26435 const T& a8, const T& a9) {
philpem@5 26436 static CImg<T> r(1,10); T *ptr = r.data;
philpem@5 26437 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26438 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26439 *(ptr++) = a8; *(ptr++) = a9;
philpem@5 26440 return r;
philpem@5 26441 }
philpem@5 26442
philpem@5 26443 //! Return a vector with specified coefficients.
philpem@5 26444 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26445 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26446 const T& a8, const T& a9, const T& a10) {
philpem@5 26447 static CImg<T> r(1,11); T *ptr = r.data;
philpem@5 26448 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26449 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26450 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10;
philpem@5 26451 return r;
philpem@5 26452 }
philpem@5 26453
philpem@5 26454 //! Return a vector with specified coefficients.
philpem@5 26455 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26456 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26457 const T& a8, const T& a9, const T& a10, const T& a11) {
philpem@5 26458 static CImg<T> r(1,12); T *ptr = r.data;
philpem@5 26459 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26460 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26461 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26462 return r;
philpem@5 26463 }
philpem@5 26464
philpem@5 26465 //! Return a vector with specified coefficients.
philpem@5 26466 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26467 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26468 const T& a8, const T& a9, const T& a10, const T& a11,
philpem@5 26469 const T& a12) {
philpem@5 26470 static CImg<T> r(1,13); T *ptr = r.data;
philpem@5 26471 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26472 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26473 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26474 *(ptr++) = a12;
philpem@5 26475 return r;
philpem@5 26476 }
philpem@5 26477
philpem@5 26478 //! Return a vector with specified coefficients.
philpem@5 26479 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26480 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26481 const T& a8, const T& a9, const T& a10, const T& a11,
philpem@5 26482 const T& a12, const T& a13) {
philpem@5 26483 static CImg<T> r(1,14); T *ptr = r.data;
philpem@5 26484 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26485 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26486 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26487 *(ptr++) = a12; *(ptr++) = a13;
philpem@5 26488 return r;
philpem@5 26489 }
philpem@5 26490
philpem@5 26491 //! Return a vector with specified coefficients.
philpem@5 26492 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26493 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26494 const T& a8, const T& a9, const T& a10, const T& a11,
philpem@5 26495 const T& a12, const T& a13, const T& a14) {
philpem@5 26496 static CImg<T> r(1,15); T *ptr = r.data;
philpem@5 26497 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26498 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26499 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26500 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
philpem@5 26501 return r;
philpem@5 26502 }
philpem@5 26503
philpem@5 26504 //! Return a vector with specified coefficients.
philpem@5 26505 static CImg<T> vector(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26506 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26507 const T& a8, const T& a9, const T& a10, const T& a11,
philpem@5 26508 const T& a12, const T& a13, const T& a14, const T& a15) {
philpem@5 26509 static CImg<T> r(1,16); T *ptr = r.data;
philpem@5 26510 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26511 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26512 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26513 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
philpem@5 26514 return r;
philpem@5 26515 }
philpem@5 26516
philpem@5 26517 //! Return a 1x1 square matrix with specified coefficients.
philpem@5 26518 static CImg<T> matrix(const T& a0) {
philpem@5 26519 return vector(a0);
philpem@5 26520 }
philpem@5 26521
philpem@5 26522 //! Return a 2x2 square matrix with specified coefficients.
philpem@5 26523 static CImg<T> matrix(const T& a0, const T& a1,
philpem@5 26524 const T& a2, const T& a3) {
philpem@5 26525 static CImg<T> r(2,2); T *ptr = r.data;
philpem@5 26526 *(ptr++) = a0; *(ptr++) = a1;
philpem@5 26527 *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26528 return r;
philpem@5 26529 }
philpem@5 26530
philpem@5 26531 //! Return a 3x3 square matrix with specified coefficients.
philpem@5 26532 static CImg<T> matrix(const T& a0, const T& a1, const T& a2,
philpem@5 26533 const T& a3, const T& a4, const T& a5,
philpem@5 26534 const T& a6, const T& a7, const T& a8) {
philpem@5 26535 static CImg<T> r(3,3); T *ptr = r.data;
philpem@5 26536 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2;
philpem@5 26537 *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5;
philpem@5 26538 *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8;
philpem@5 26539 return r;
philpem@5 26540 }
philpem@5 26541
philpem@5 26542 //! Return a 4x4 square matrix with specified coefficients.
philpem@5 26543 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3,
philpem@5 26544 const T& a4, const T& a5, const T& a6, const T& a7,
philpem@5 26545 const T& a8, const T& a9, const T& a10, const T& a11,
philpem@5 26546 const T& a12, const T& a13, const T& a14, const T& a15) {
philpem@5 26547 static CImg<T> r(4,4); T *ptr = r.data;
philpem@5 26548 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3;
philpem@5 26549 *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7;
philpem@5 26550 *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11;
philpem@5 26551 *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15;
philpem@5 26552 return r;
philpem@5 26553 }
philpem@5 26554
philpem@5 26555 //! Return a 5x5 square matrix with specified coefficients.
philpem@5 26556 static CImg<T> matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4,
philpem@5 26557 const T& a5, const T& a6, const T& a7, const T& a8, const T& a9,
philpem@5 26558 const T& a10, const T& a11, const T& a12, const T& a13, const T& a14,
philpem@5 26559 const T& a15, const T& a16, const T& a17, const T& a18, const T& a19,
philpem@5 26560 const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) {
philpem@5 26561 static CImg<T> r(5,5); T *ptr = r.data;
philpem@5 26562 *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4;
philpem@5 26563 *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9;
philpem@5 26564 *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14;
philpem@5 26565 *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19;
philpem@5 26566 *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24;
philpem@5 26567 return r;
philpem@5 26568 }
philpem@5 26569
philpem@5 26570 //! Return a 1x1 symmetric matrix with specified coefficients.
philpem@5 26571 static CImg<T> tensor(const T& a1) {
philpem@5 26572 return matrix(a1);
philpem@5 26573 }
philpem@5 26574
philpem@5 26575 //! Return a 2x2 symmetric matrix tensor with specified coefficients.
philpem@5 26576 static CImg<T> tensor(const T& a1, const T& a2, const T& a3) {
philpem@5 26577 return matrix(a1,a2,a2,a3);
philpem@5 26578 }
philpem@5 26579
philpem@5 26580 //! Return a 3x3 symmetric matrix with specified coefficients.
philpem@5 26581 static CImg<T> tensor(const T& a1, const T& a2, const T& a3, const T& a4, const T& a5, const T& a6) {
philpem@5 26582 return matrix(a1,a2,a3,a2,a4,a5,a3,a5,a6);
philpem@5 26583 }
philpem@5 26584
philpem@5 26585 //! Return a 1x1 diagonal matrix with specified coefficients.
philpem@5 26586 static CImg<T> diagonal(const T& a0) {
philpem@5 26587 return matrix(a0);
philpem@5 26588 }
philpem@5 26589
philpem@5 26590 //! Return a 2x2 diagonal matrix with specified coefficients.
philpem@5 26591 static CImg<T> diagonal(const T& a0, const T& a1) {
philpem@5 26592 return matrix(a0,0,0,a1);
philpem@5 26593 }
philpem@5 26594
philpem@5 26595 //! Return a 3x3 diagonal matrix with specified coefficients.
philpem@5 26596 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2) {
philpem@5 26597 return matrix(a0,0,0,0,a1,0,0,0,a2);
philpem@5 26598 }
philpem@5 26599
philpem@5 26600 //! Return a 4x4 diagonal matrix with specified coefficients.
philpem@5 26601 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3) {
philpem@5 26602 return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3);
philpem@5 26603 }
philpem@5 26604
philpem@5 26605 //! Return a 5x5 diagonal matrix with specified coefficients.
philpem@5 26606 static CImg<T> diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) {
philpem@5 26607 return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4);
philpem@5 26608 }
philpem@5 26609
philpem@5 26610 //! Return a NxN identity matrix.
philpem@5 26611 static CImg<T> identity_matrix(const unsigned int N) {
philpem@5 26612 CImg<T> res(N,N,1,1,0);
philpem@5 26613 cimg_forX(res,x) res(x,x) = 1;
philpem@5 26614 return res;
philpem@5 26615 }
philpem@5 26616
philpem@5 26617 //! Return a N-numbered sequence vector from \p a0 to \p a1.
philpem@5 26618 static CImg<T> sequence(const unsigned int N, const T a0, const T a1) {
philpem@5 26619 if (N) return CImg<T>(1,N).sequence(a0,a1);
philpem@5 26620 return CImg<T>();
philpem@5 26621 }
philpem@5 26622
philpem@5 26623 //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w.
philpem@5 26624 static CImg<T> rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) {
philpem@5 26625 float X,Y,Z,W;
philpem@5 26626 if (!quaternion_data) {
philpem@5 26627 const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z),
philpem@5 26628 nx = norm>0?x/norm:0,
philpem@5 26629 ny = norm>0?y/norm:0,
philpem@5 26630 nz = norm>0?z/norm:1,
philpem@5 26631 nw = norm>0?w:0,
philpem@5 26632 sina = (float)cimg_std::sin(nw/2),
philpem@5 26633 cosa = (float)cimg_std::cos(nw/2);
philpem@5 26634 X = nx*sina;
philpem@5 26635 Y = ny*sina;
philpem@5 26636 Z = nz*sina;
philpem@5 26637 W = cosa;
philpem@5 26638 } else {
philpem@5 26639 const float norm = (float)cimg_std::sqrt(x*x + y*y + z*z + w*w);
philpem@5 26640 if (norm>0) { X = x/norm; Y = y/norm; Z = z/norm; W = w/norm; }
philpem@5 26641 else { X = Y = Z = 0; W = 1; }
philpem@5 26642 }
philpem@5 26643 const float xx = X*X, xy = X*Y, xz = X*Z, xw = X*W, yy = Y*Y, yz = Y*Z, yw = Y*W, zz = Z*Z, zw = Z*W;
philpem@5 26644 return CImg<T>::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)),
philpem@5 26645 (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)),
philpem@5 26646 (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy)));
philpem@5 26647 }
philpem@5 26648
philpem@5 26649 //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26650 CImg<T> get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
philpem@5 26651 static CImg<T> dest;
philpem@5 26652 if (dest.height!=dim) dest.assign(1,dim);
philpem@5 26653 const unsigned int whz = width*height*depth;
philpem@5 26654 const T *ptrs = ptr(x,y,z);
philpem@5 26655 T *ptrd = dest.data;
philpem@5 26656 cimg_forV(*this,k) { *(ptrd++) = *ptrs; ptrs+=whz; }
philpem@5 26657 return dest;
philpem@5 26658 }
philpem@5 26659
philpem@5 26660 //! Set the image \p vec as the \a vector \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26661 template<typename t>
philpem@5 26662 CImg<T>& set_vector_at(const CImg<t>& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) {
philpem@5 26663 if (x<width && y<height && z<depth) {
philpem@5 26664 const unsigned int whz = width*height*depth;
philpem@5 26665 const t *ptrs = vec.data;
philpem@5 26666 T *ptrd = ptr(x,y,z);
philpem@5 26667 for (unsigned int k=cimg::min((unsigned int)vec.size(),dim); k; --k) { *ptrd = (T)*(ptrs++); ptrd+=whz; }
philpem@5 26668 }
philpem@5 26669 return *this;
philpem@5 26670 }
philpem@5 26671
philpem@5 26672 //! Return a new image corresponding to the \a square \a matrix located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26673 CImg<T> get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const {
philpem@5 26674 const int n = (int)cimg_std::sqrt((double)dim);
philpem@5 26675 CImg<T> dest(n,n);
philpem@5 26676 cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k);
philpem@5 26677 return dest;
philpem@5 26678 }
philpem@5 26679
philpem@5 26680 //! Set the image \p vec as the \a square \a matrix-valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26681 template<typename t>
philpem@5 26682 CImg<T>& set_matrix_at(const CImg<t>& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
philpem@5 26683 return set_vector_at(mat,x,y,z);
philpem@5 26684 }
philpem@5 26685
philpem@5 26686 //! Return a new image corresponding to the \a diffusion \a tensor located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26687 CImg<T> get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const {
philpem@5 26688 if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2),
philpem@5 26689 (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5));
philpem@5 26690 if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2));
philpem@5 26691 return tensor((*this)(x,y,z,0));
philpem@5 26692 }
philpem@5 26693
philpem@5 26694 //! Set the image \p vec as the \a tensor \a valued pixel located at (\p x,\p y,\p z) of the current vector-valued image.
philpem@5 26695 template<typename t>
philpem@5 26696 CImg<T>& set_tensor_at(const CImg<t>& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) {
philpem@5 26697 if (ten.height==2) {
philpem@5 26698 (*this)(x,y,z,0) = (T)ten[0];
philpem@5 26699 (*this)(x,y,z,1) = (T)ten[1];
philpem@5 26700 (*this)(x,y,z,2) = (T)ten[3];
philpem@5 26701 }
philpem@5 26702 else {
philpem@5 26703 (*this)(x,y,z,0) = (T)ten[0];
philpem@5 26704 (*this)(x,y,z,1) = (T)ten[1];
philpem@5 26705 (*this)(x,y,z,2) = (T)ten[2];
philpem@5 26706 (*this)(x,y,z,3) = (T)ten[4];
philpem@5 26707 (*this)(x,y,z,4) = (T)ten[5];
philpem@5 26708 (*this)(x,y,z,5) = (T)ten[8];
philpem@5 26709 }
philpem@5 26710 return *this;
philpem@5 26711 }
philpem@5 26712
philpem@5 26713 //! Unroll all images values into a one-column vector.
philpem@5 26714 CImg<T>& vector() {
philpem@5 26715 return unroll('y');
philpem@5 26716 }
philpem@5 26717
philpem@5 26718 CImg<T> get_vector() const {
philpem@5 26719 return get_unroll('y');
philpem@5 26720 }
philpem@5 26721
philpem@5 26722 //! Realign pixel values of the instance image as a square matrix
philpem@5 26723 CImg<T>& matrix() {
philpem@5 26724 const unsigned int siz = size();
philpem@5 26725 switch (siz) {
philpem@5 26726 case 1 : break;
philpem@5 26727 case 4 : width = height = 2; break;
philpem@5 26728 case 9 : width = height = 3; break;
philpem@5 26729 case 16 : width = height = 4; break;
philpem@5 26730 case 25 : width = height = 5; break;
philpem@5 26731 case 36 : width = height = 6; break;
philpem@5 26732 case 49 : width = height = 7; break;
philpem@5 26733 case 64 : width = height = 8; break;
philpem@5 26734 case 81 : width = height = 9; break;
philpem@5 26735 case 100 : width = height = 10; break;
philpem@5 26736 default : {
philpem@5 26737 unsigned int i = 11, i2 = i*i;
philpem@5 26738 while (i2<siz) { i2+=2*i+1; ++i; }
philpem@5 26739 if (i2==siz) width = height = i;
philpem@5 26740 else throw CImgInstanceException("CImg<%s>::matrix() : Image size = %u is not a square number",
philpem@5 26741 pixel_type(),siz);
philpem@5 26742 }
philpem@5 26743 }
philpem@5 26744 return *this;
philpem@5 26745 }
philpem@5 26746
philpem@5 26747 CImg<T> get_matrix() const {
philpem@5 26748 return (+*this).matrix();
philpem@5 26749 }
philpem@5 26750
philpem@5 26751 //! Realign pixel values of the instance image as a symmetric tensor.
philpem@5 26752 CImg<T>& tensor() {
philpem@5 26753 return get_tensor().transfer_to(*this);
philpem@5 26754 }
philpem@5 26755
philpem@5 26756 CImg<T> get_tensor() const {
philpem@5 26757 CImg<T> res;
philpem@5 26758 const unsigned int siz = size();
philpem@5 26759 switch (siz) {
philpem@5 26760 case 1 : break;
philpem@5 26761 case 3 :
philpem@5 26762 res.assign(2,2);
philpem@5 26763 res(0,0) = (*this)(0);
philpem@5 26764 res(1,0) = res(0,1) = (*this)(1);
philpem@5 26765 res(1,1) = (*this)(2);
philpem@5 26766 break;
philpem@5 26767 case 6 :
philpem@5 26768 res.assign(3,3);
philpem@5 26769 res(0,0) = (*this)(0);
philpem@5 26770 res(1,0) = res(0,1) = (*this)(1);
philpem@5 26771 res(2,0) = res(0,2) = (*this)(2);
philpem@5 26772 res(1,1) = (*this)(3);
philpem@5 26773 res(2,1) = res(1,2) = (*this)(4);
philpem@5 26774 res(2,2) = (*this)(5);
philpem@5 26775 break;
philpem@5 26776 default :
philpem@5 26777 throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.",
philpem@5 26778 pixel_type(), dim);
philpem@5 26779 }
philpem@5 26780 return res;
philpem@5 26781 }
philpem@5 26782
philpem@5 26783 //! Unroll all images values into specified axis.
philpem@5 26784 CImg<T>& unroll(const char axis) {
philpem@5 26785 const unsigned int siz = size();
philpem@5 26786 if (siz) switch (axis) {
philpem@5 26787 case 'x' : width = siz; height=depth=dim=1; break;
philpem@5 26788 case 'y' : height = siz; width=depth=dim=1; break;
philpem@5 26789 case 'z' : depth = siz; width=height=dim=1; break;
philpem@5 26790 case 'v' : dim = siz; width=height=depth=1; break;
philpem@5 26791 default :
philpem@5 26792 throw CImgArgumentException("CImg<%s>::unroll() : Given axis is '%c' which is not 'x','y','z' or 'v'",
philpem@5 26793 pixel_type(),axis);
philpem@5 26794 }
philpem@5 26795 return *this;
philpem@5 26796 }
philpem@5 26797
philpem@5 26798 CImg<T> get_unroll(const char axis) const {
philpem@5 26799 return (+*this).unroll(axis);
philpem@5 26800 }
philpem@5 26801
philpem@5 26802 //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image.
philpem@5 26803 CImg<T>& diagonal() {
philpem@5 26804 return get_diagonal().transfer_to(*this);
philpem@5 26805 }
philpem@5 26806
philpem@5 26807 CImg<T> get_diagonal() const {
philpem@5 26808 if (is_empty()) return *this;
philpem@5 26809 CImg<T> res(size(),size(),1,1,0);
philpem@5 26810 cimg_foroff(*this,off) res(off,off) = (*this)(off);
philpem@5 26811 return res;
philpem@5 26812 }
philpem@5 26813
philpem@5 26814 //! Get an identity matrix having same dimension than instance image.
philpem@5 26815 CImg<T>& identity_matrix() {
philpem@5 26816 return identity_matrix(cimg::max(width,height)).transfer_to(*this);
philpem@5 26817 }
philpem@5 26818
philpem@5 26819 CImg<T> get_identity_matrix() const {
philpem@5 26820 return identity_matrix(cimg::max(width,height));
philpem@5 26821 }
philpem@5 26822
philpem@5 26823 //! Return a N-numbered sequence vector from \p a0 to \p a1.
philpem@5 26824 CImg<T>& sequence(const T a0, const T a1) {
philpem@5 26825 if (is_empty()) return *this;
philpem@5 26826 const unsigned int siz = size() - 1;
philpem@5 26827 T* ptr = data;
philpem@5 26828 if (siz) {
philpem@5 26829 const Tfloat delta = (Tfloat)a1 - a0;
philpem@5 26830 cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz);
philpem@5 26831 } else *ptr = a0;
philpem@5 26832 return *this;
philpem@5 26833 }
philpem@5 26834
philpem@5 26835 CImg<T> get_sequence(const T a0, const T a1) const {
philpem@5 26836 return (+*this).sequence(a0,a1);
philpem@5 26837 }
philpem@5 26838
philpem@5 26839 //! Transpose the current matrix.
philpem@5 26840 CImg<T>& transpose() {
philpem@5 26841 if (width==1) { width=height; height=1; return *this; }
philpem@5 26842 if (height==1) { height=width; width=1; return *this; }
philpem@5 26843 if (width==height) {
philpem@5 26844 cimg_forYZV(*this,y,z,v) for (int x=y; x<dimx(); ++x) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v));
philpem@5 26845 return *this;
philpem@5 26846 }
philpem@5 26847 return get_transpose().transfer_to(*this);
philpem@5 26848 }
philpem@5 26849
philpem@5 26850 CImg<T> get_transpose() const {
philpem@5 26851 return get_permute_axes("yxzv");
philpem@5 26852 }
philpem@5 26853
philpem@5 26854 //! Invert the current matrix.
philpem@5 26855 CImg<T>& invert(const bool use_LU=true) {
philpem@5 26856 if (!is_empty()) {
philpem@5 26857 if (width!=height || depth!=1 || dim!=1)
philpem@5 26858 throw CImgInstanceException("CImg<%s>::invert() : Instance matrix (%u,%u,%u,%u,%p) is not square.",
philpem@5 26859 pixel_type(),width,height,depth,dim,data);
philpem@5 26860 #ifdef cimg_use_lapack
philpem@5 26861 int INFO = (int)use_LU, N = width, LWORK = 4*N, *IPIV = new int[N];
philpem@5 26862 Tfloat
philpem@5 26863 *lapA = new Tfloat[N*N],
philpem@5 26864 *WORK = new Tfloat[LWORK];
philpem@5 26865 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
philpem@5 26866 cimg::getrf(N,lapA,IPIV,INFO);
philpem@5 26867 if (INFO)
philpem@5 26868 cimg::warn("CImg<%s>::invert() : LAPACK library function dgetrf_() returned error code %d.",
philpem@5 26869 pixel_type(),INFO);
philpem@5 26870 else {
philpem@5 26871 cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
philpem@5 26872 if (INFO)
philpem@5 26873 cimg::warn("CImg<%s>::invert() : LAPACK library function dgetri_() returned Error code %d",
philpem@5 26874 pixel_type(),INFO);
philpem@5 26875 }
philpem@5 26876 if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N+l]); else fill(0);
philpem@5 26877 delete[] IPIV; delete[] lapA; delete[] WORK;
philpem@5 26878 #else
philpem@5 26879 const double dete = width>3?-1.0:det();
philpem@5 26880 if (dete!=0.0 && width==2) {
philpem@5 26881 const double
philpem@5 26882 a = data[0], c = data[1],
philpem@5 26883 b = data[2], d = data[3];
philpem@5 26884 data[0] = (T)(d/dete); data[1] = (T)(-c/dete);
philpem@5 26885 data[2] = (T)(-b/dete); data[3] = (T)(a/dete);
philpem@5 26886 } else if (dete!=0.0 && width==3) {
philpem@5 26887 const double
philpem@5 26888 a = data[0], d = data[1], g = data[2],
philpem@5 26889 b = data[3], e = data[4], h = data[5],
philpem@5 26890 c = data[6], f = data[7], i = data[8];
philpem@5 26891 data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete);
philpem@5 26892 data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete);
philpem@5 26893 data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete);
philpem@5 26894 } else {
philpem@5 26895 if (use_LU) { // LU-based inverse computation
philpem@5 26896 CImg<Tfloat> A(*this), indx, col(1,width);
philpem@5 26897 bool d;
philpem@5 26898 A._LU(indx,d);
philpem@5 26899 cimg_forX(*this,j) {
philpem@5 26900 col.fill(0);
philpem@5 26901 col(j) = 1;
philpem@5 26902 col._solve(A,indx);
philpem@5 26903 cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
philpem@5 26904 }
philpem@5 26905 } else { // SVD-based inverse computation
philpem@5 26906 CImg<Tfloat> U(width,width), S(1,width), V(width,width);
philpem@5 26907 SVD(U,S,V,false);
philpem@5 26908 U.transpose();
philpem@5 26909 cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k];
philpem@5 26910 S.diagonal();
philpem@5 26911 *this = V*S*U;
philpem@5 26912 }
philpem@5 26913 }
philpem@5 26914 #endif
philpem@5 26915 }
philpem@5 26916 return *this;
philpem@5 26917 }
philpem@5 26918
philpem@5 26919 CImg<Tfloat> get_invert(const bool use_LU=true) const {
philpem@5 26920 return CImg<Tfloat>(*this,false).invert(use_LU);
philpem@5 26921 }
philpem@5 26922
philpem@5 26923 //! Compute the pseudo-inverse (Moore-Penrose) of the matrix.
philpem@5 26924 CImg<T>& pseudoinvert() {
philpem@5 26925 return get_pseudoinvert().transfer_to(*this);
philpem@5 26926 }
philpem@5 26927
philpem@5 26928 CImg<Tfloat> get_pseudoinvert() const {
philpem@5 26929 CImg<Tfloat> U, S, V;
philpem@5 26930 SVD(U,S,V);
philpem@5 26931 cimg_forX(V,x) {
philpem@5 26932 const Tfloat s = S(x), invs = s!=0?1/s:(Tfloat)0;
philpem@5 26933 cimg_forY(V,y) V(x,y)*=invs;
philpem@5 26934 }
philpem@5 26935 return V*U.transpose();
philpem@5 26936 }
philpem@5 26937
philpem@5 26938 //! Compute the cross product between two 3d vectors.
philpem@5 26939 template<typename t>
philpem@5 26940 CImg<T>& cross(const CImg<t>& img) {
philpem@5 26941 if (width!=1 || height<3 || img.width!=1 || img.height<3)
philpem@5 26942 throw CImgInstanceException("CImg<%s>::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.",
philpem@5 26943 pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data);
philpem@5 26944 const T x = (*this)[0], y = (*this)[1], z = (*this)[2];
philpem@5 26945 (*this)[0] = (T)(y*img[2]-z*img[1]);
philpem@5 26946 (*this)[1] = (T)(z*img[0]-x*img[2]);
philpem@5 26947 (*this)[2] = (T)(x*img[1]-y*img[0]);
philpem@5 26948 return *this;
philpem@5 26949 }
philpem@5 26950
philpem@5 26951 template<typename t>
philpem@5 26952 CImg<typename cimg::superset<T,t>::type> get_cross(const CImg<t>& img) const {
philpem@5 26953 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 26954 return CImg<Tt>(*this).cross(img);
philpem@5 26955 }
philpem@5 26956
philpem@5 26957 //! Solve a linear system AX=B where B=*this.
philpem@5 26958 template<typename t>
philpem@5 26959 CImg<T>& solve(const CImg<t>& A) {
philpem@5 26960 if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1)
philpem@5 26961 throw CImgArgumentException("CImg<%s>::solve() : Instance matrix size is (%u,%u,%u,%u) while "
philpem@5 26962 "size of given matrix A is (%u,%u,%u,%u).",
philpem@5 26963 pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim);
philpem@5 26964
philpem@5 26965 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 26966 if (A.width==A.height) {
philpem@5 26967 #ifdef cimg_use_lapack
philpem@5 26968 char TRANS='N';
philpem@5 26969 int INFO, N = height, LWORK = 4*N, one = 1, *IPIV = new int[N];
philpem@5 26970 Ttfloat
philpem@5 26971 *lapA = new Ttfloat[N*N],
philpem@5 26972 *lapB = new Ttfloat[N],
philpem@5 26973 *WORK = new Ttfloat[LWORK];
philpem@5 26974 cimg_forXY(A,k,l) lapA[k*N+l] = (Ttfloat)(A(k,l));
philpem@5 26975 cimg_forY(*this,i) lapB[i] = (Ttfloat)((*this)(i));
philpem@5 26976 cimg::getrf(N,lapA,IPIV,INFO);
philpem@5 26977 if (INFO)
philpem@5 26978 cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrf_() returned error code %d.",
philpem@5 26979 pixel_type(),INFO);
philpem@5 26980 if (!INFO) {
philpem@5 26981 cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO);
philpem@5 26982 if (INFO)
philpem@5 26983 cimg::warn("CImg<%s>::solve() : LAPACK library function dgetrs_() returned Error code %d",
philpem@5 26984 pixel_type(),INFO);
philpem@5 26985 }
philpem@5 26986 if (!INFO) cimg_forY(*this,i) (*this)(i) = (T)(lapB[i]); else fill(0);
philpem@5 26987 delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK;
philpem@5 26988 #else
philpem@5 26989 CImg<Ttfloat> lu(A);
philpem@5 26990 CImg<Ttfloat> indx;
philpem@5 26991 bool d;
philpem@5 26992 lu._LU(indx,d);
philpem@5 26993 _solve(lu,indx);
philpem@5 26994 #endif
philpem@5 26995 } else assign(A.get_pseudoinvert()*(*this));
philpem@5 26996 return *this;
philpem@5 26997 }
philpem@5 26998
philpem@5 26999 template<typename t>
philpem@5 27000 CImg<typename cimg::superset2<T,t,float>::type> get_solve(const CImg<t>& A) const {
philpem@5 27001 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 27002 return CImg<Ttfloat>(*this,false).solve(A);
philpem@5 27003 }
philpem@5 27004
philpem@5 27005 template<typename t, typename ti>
philpem@5 27006 CImg<T>& _solve(const CImg<t>& A, const CImg<ti>& indx) {
philpem@5 27007 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 27008 const int N = size();
philpem@5 27009 int ii = -1;
philpem@5 27010 Ttfloat sum;
philpem@5 27011 for (int i=0; i<N; ++i) {
philpem@5 27012 const int ip = (int)indx[i];
philpem@5 27013 Ttfloat sum = (*this)(ip);
philpem@5 27014 (*this)(ip) = (*this)(i);
philpem@5 27015 if (ii>=0) for (int j=ii; j<=i-1; ++j) sum-=A(j,i)*(*this)(j);
philpem@5 27016 else if (sum!=0) ii=i;
philpem@5 27017 (*this)(i) = (T)sum;
philpem@5 27018 }
philpem@5 27019 { for (int i=N-1; i>=0; --i) {
philpem@5 27020 sum = (*this)(i);
philpem@5 27021 for (int j=i+1; j<N; ++j) sum-=A(j,i)*(*this)(j);
philpem@5 27022 (*this)(i) = (T)(sum/A(i,i));
philpem@5 27023 }}
philpem@5 27024 return *this;
philpem@5 27025 }
philpem@5 27026
philpem@5 27027 //! Solve a linear system AX=B where B=*this and A is a tridiagonal matrix A = [ b0,c0,0,...; a1,b1,c1,0,... ; ... ; ...,0,aN,bN ].
philpem@5 27028 // (Use the Thomas Algorithm).
philpem@5 27029 template<typename t>
philpem@5 27030 CImg<T>& solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) {
philpem@5 27031 const int siz = (int)size();
philpem@5 27032 if ((int)a.size()!=siz || (int)b.size()!=siz || (int)c.size()!=siz)
philpem@5 27033 throw CImgArgumentException("CImg<%s>::solve_tridiagonal() : arrays of triagonal coefficients have different size.",pixel_type);
philpem@5 27034 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 27035 CImg<Ttfloat> nc(siz);
philpem@5 27036 const T *ptra = a.data, *ptrb = b.data, *ptrc = c.data;
philpem@5 27037 T *ptrnc = nc.data, *ptrd = data;
philpem@5 27038 const Ttfloat valb0 = (Ttfloat)*(ptrb++);
philpem@5 27039 *ptrnc = *(ptrc++)/valb0;
philpem@5 27040 Ttfloat vald = (Ttfloat)(*(ptrd++)/=valb0);
philpem@5 27041 for (int i = 1; i<siz; ++i) {
philpem@5 27042 const Ttfloat
philpem@5 27043 vala = (Tfloat)*(ptra++),
philpem@5 27044 id = 1/(*(ptrb++) - *(ptrnc++)*vala);
philpem@5 27045 *ptrnc = *(ptrc++)*id;
philpem@5 27046 vald = ((*ptrd-=vala*vald)*=id);
philpem@5 27047 ++ptrd;
philpem@5 27048 }
philpem@5 27049 vald = *(--ptrd);
philpem@5 27050 for (int i = siz-2; i>=0; --i) vald = (*(--ptrd)-=*(--ptrnc)*vald);
philpem@5 27051 return *this;
philpem@5 27052 }
philpem@5 27053
philpem@5 27054 template<typename t>
philpem@5 27055 CImg<typename cimg::superset2<T,t,float>::type> get_solve_tridiagonal(const CImg<t>& a, const CImg<t>& b, const CImg<t>& c) const {
philpem@5 27056 typedef typename cimg::superset2<T,t,float>::type Ttfloat;
philpem@5 27057 return CImg<Ttfloat>(*this,false).solve_tridiagonal(a,b,c);
philpem@5 27058 }
philpem@5 27059
philpem@5 27060 //! Sort values of a vector and get permutations.
philpem@5 27061 template<typename t>
philpem@5 27062 CImg<T>& sort(CImg<t>& permutations, const bool increasing=true) {
philpem@5 27063 if (is_empty()) permutations.assign();
philpem@5 27064 else {
philpem@5 27065 if (permutations.size()!=size()) permutations.assign(size());
philpem@5 27066 cimg_foroff(permutations,off) permutations[off] = (t)off;
philpem@5 27067 _quicksort(0,size()-1,permutations,increasing);
philpem@5 27068 }
philpem@5 27069 return *this;
philpem@5 27070 }
philpem@5 27071
philpem@5 27072 template<typename t>
philpem@5 27073 CImg<T> get_sort(CImg<t>& permutations, const bool increasing=true) const {
philpem@5 27074 return (+*this).sort(permutations,increasing);
philpem@5 27075 }
philpem@5 27076
philpem@5 27077 // Sort image values.
philpem@5 27078 CImg<T>& sort(const bool increasing=true) {
philpem@5 27079 CImg<T> foo;
philpem@5 27080 return sort(foo,increasing);
philpem@5 27081 }
philpem@5 27082
philpem@5 27083 CImg<T> get_sort(const bool increasing=true) const {
philpem@5 27084 return (+*this).sort(increasing);
philpem@5 27085 }
philpem@5 27086
philpem@5 27087 template<typename t>
philpem@5 27088 CImg<T>& _quicksort(const int min, const int max, CImg<t>& permutations, const bool increasing) {
philpem@5 27089 if (min<max) {
philpem@5 27090 const int mid = (min+max)/2;
philpem@5 27091 if (increasing) {
philpem@5 27092 if ((*this)[min]>(*this)[mid]) {
philpem@5 27093 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
philpem@5 27094 if ((*this)[mid]>(*this)[max]) {
philpem@5 27095 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
philpem@5 27096 if ((*this)[min]>(*this)[mid]) {
philpem@5 27097 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
philpem@5 27098 } else {
philpem@5 27099 if ((*this)[min]<(*this)[mid]) {
philpem@5 27100 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
philpem@5 27101 if ((*this)[mid]<(*this)[max]) {
philpem@5 27102 cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); }
philpem@5 27103 if ((*this)[min]<(*this)[mid]) {
philpem@5 27104 cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); }
philpem@5 27105 }
philpem@5 27106 if (max-min>=3) {
philpem@5 27107 const T pivot = (*this)[mid];
philpem@5 27108 int i = min, j = max;
philpem@5 27109 if (increasing) {
philpem@5 27110 do {
philpem@5 27111 while ((*this)[i]<pivot) ++i;
philpem@5 27112 while ((*this)[j]>pivot) --j;
philpem@5 27113 if (i<=j) {
philpem@5 27114 cimg::swap((*this)[i],(*this)[j]);
philpem@5 27115 cimg::swap(permutations[i++],permutations[j--]);
philpem@5 27116 }
philpem@5 27117 } while (i<=j);
philpem@5 27118 } else {
philpem@5 27119 do {
philpem@5 27120 while ((*this)[i]>pivot) ++i;
philpem@5 27121 while ((*this)[j]<pivot) --j;
philpem@5 27122 if (i<=j) {
philpem@5 27123 cimg::swap((*this)[i],(*this)[j]);
philpem@5 27124 cimg::swap(permutations[i++],permutations[j--]);
philpem@5 27125 }
philpem@5 27126 } while (i<=j);
philpem@5 27127 }
philpem@5 27128 if (min<j) _quicksort(min,j,permutations,increasing);
philpem@5 27129 if (i<max) _quicksort(i,max,permutations,increasing);
philpem@5 27130 }
philpem@5 27131 }
philpem@5 27132 return *this;
philpem@5 27133 }
philpem@5 27134
philpem@5 27135 //! Get a permutation of the pixels.
philpem@5 27136 template<typename t>
philpem@5 27137 CImg<T>& permute(const CImg<t>& permutation) {
philpem@5 27138 return get_permute(permutation).transfer_to(*this);
philpem@5 27139 }
philpem@5 27140
philpem@5 27141 template<typename t>
philpem@5 27142 CImg<T> get_permute(const CImg<t>& permutation) const {
philpem@5 27143 if (permutation.size()!=size())
philpem@5 27144 throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)"
philpem@5 27145 "have different sizes.",
philpem@5 27146 pixel_type(),width,height,depth,dim,data,
philpem@5 27147 permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data);
philpem@5 27148 CImg<T> res(width,height,depth,dim);
philpem@5 27149 const t *p = permutation.ptr(permutation.size());
philpem@5 27150 cimg_for(res,ptr,T) *ptr = (*this)[*(--p)];
philpem@5 27151 return res;
philpem@5 27152 }
philpem@5 27153
philpem@5 27154 //! Compute the SVD of a general matrix.
philpem@5 27155 template<typename t>
philpem@5 27156 const CImg<T>& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& V,
philpem@5 27157 const bool sorting=true, const unsigned int max_iter=40, const float lambda=0) const {
philpem@5 27158 if (is_empty()) { U.assign(); S.assign(); V.assign(); }
philpem@5 27159 else {
philpem@5 27160 U = *this;
philpem@5 27161 if (lambda!=0) {
philpem@5 27162 const unsigned int delta = cimg::min(U.width,U.height);
philpem@5 27163 for (unsigned int i=0; i<delta; ++i) U(i,i) = (t)(U(i,i) + lambda);
philpem@5 27164 }
philpem@5 27165 if (S.size()<width) S.assign(1,width);
philpem@5 27166 if (V.width<width || V.height<height) V.assign(width,width);
philpem@5 27167 CImg<t> rv1(width);
philpem@5 27168 t anorm = 0, c, f, g = 0, h, s, scale = 0;
philpem@5 27169 int l = 0, nm = 0;
philpem@5 27170
philpem@5 27171 cimg_forX(U,i) {
philpem@5 27172 l = i+1; rv1[i] = scale*g; g = s = scale = 0;
philpem@5 27173 if (i<dimy()) {
philpem@5 27174 for (int k=i; k<dimy(); ++k) scale+= cimg::abs(U(i,k));
philpem@5 27175 if (scale) {
philpem@5 27176 for (int k=i; k<dimy(); ++k) { U(i,k)/=scale; s+= U(i,k)*U(i,k); }
philpem@5 27177 f = U(i,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h=f*g-s; U(i,i) = f-g;
philpem@5 27178 for (int j=l; j<dimx(); ++j) {
philpem@5 27179 s = 0; for (int k=i; k<dimy(); ++k) s+= U(i,k)*U(j,k);
philpem@5 27180 f = s/h;
philpem@5 27181 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
philpem@5 27182 }
philpem@5 27183 { for (int k=i; k<dimy(); ++k) U(i,k)*= scale; }
philpem@5 27184 }
philpem@5 27185 }
philpem@5 27186 S[i]=scale*g;
philpem@5 27187
philpem@5 27188 g = s = scale = 0;
philpem@5 27189 if (i<dimy() && i!=dimx()-1) {
philpem@5 27190 for (int k=l; k<dimx(); ++k) scale += cimg::abs(U(k,i));
philpem@5 27191 if (scale) {
philpem@5 27192 for (int k=l; k<dimx(); ++k) { U(k,i)/= scale; s+= U(k,i)*U(k,i); }
philpem@5 27193 f = U(l,i); g = (t)((f>=0?-1:1)*cimg_std::sqrt(s)); h = f*g-s; U(l,i) = f-g;
philpem@5 27194 { for (int k=l; k<dimx(); ++k) rv1[k]=U(k,i)/h; }
philpem@5 27195 for (int j=l; j<dimy(); ++j) {
philpem@5 27196 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,j)*U(k,i);
philpem@5 27197 { for (int k=l; k<dimx(); ++k) U(k,j)+= s*rv1[k]; }
philpem@5 27198 }
philpem@5 27199 { for (int k=l; k<dimx(); ++k) U(k,i)*= scale; }
philpem@5 27200 }
philpem@5 27201 }
philpem@5 27202 anorm = (t)cimg::max((float)anorm,(float)(cimg::abs(S[i])+cimg::abs(rv1[i])));
philpem@5 27203 }
philpem@5 27204
philpem@5 27205 { for (int i=dimx()-1; i>=0; --i) {
philpem@5 27206 if (i<dimx()-1) {
philpem@5 27207 if (g) {
philpem@5 27208 { for (int j=l; j<dimx(); ++j) V(i,j) =(U(j,i)/U(l,i))/g; }
philpem@5 27209 for (int j=l; j<dimx(); ++j) {
philpem@5 27210 s = 0; for (int k=l; k<dimx(); ++k) s+= U(k,i)*V(j,k);
philpem@5 27211 { for (int k=l; k<dimx(); ++k) V(j,k)+= s*V(i,k); }
philpem@5 27212 }
philpem@5 27213 }
philpem@5 27214 for (int j=l; j<dimx(); ++j) V(j,i) = V(i,j) = (t)0.0;
philpem@5 27215 }
philpem@5 27216 V(i,i) = (t)1.0; g = rv1[i]; l = i;
philpem@5 27217 }
philpem@5 27218 }
philpem@5 27219
philpem@5 27220 { for (int i=cimg::min(dimx(),dimy())-1; i>=0; --i) {
philpem@5 27221 l = i+1; g = S[i];
philpem@5 27222 for (int j=l; j<dimx(); ++j) U(j,i) = 0;
philpem@5 27223 if (g) {
philpem@5 27224 g = 1/g;
philpem@5 27225 for (int j=l; j<dimx(); ++j) {
philpem@5 27226 s = 0; for (int k=l; k<dimy(); ++k) s+= U(i,k)*U(j,k);
philpem@5 27227 f = (s/U(i,i))*g;
philpem@5 27228 { for (int k=i; k<dimy(); ++k) U(j,k)+= f*U(i,k); }
philpem@5 27229 }
philpem@5 27230 { for (int j=i; j<dimy(); ++j) U(i,j)*= g; }
philpem@5 27231 } else for (int j=i; j<dimy(); ++j) U(i,j) = 0;
philpem@5 27232 ++U(i,i);
philpem@5 27233 }
philpem@5 27234 }
philpem@5 27235
philpem@5 27236 for (int k=dimx()-1; k>=0; --k) {
philpem@5 27237 for (unsigned int its=0; its<max_iter; ++its) {
philpem@5 27238 bool flag = true;
philpem@5 27239 for (l=k; l>=1; --l) {
philpem@5 27240 nm = l-1;
philpem@5 27241 if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; }
philpem@5 27242 if ((cimg::abs(S[nm])+anorm)==anorm) break;
philpem@5 27243 }
philpem@5 27244 if (flag) {
philpem@5 27245 c = 0; s = 1;
philpem@5 27246 for (int i=l; i<=k; ++i) {
philpem@5 27247 f = s*rv1[i]; rv1[i] = c*rv1[i];
philpem@5 27248 if ((cimg::abs(f)+anorm)==anorm) break;
philpem@5 27249 g = S[i]; h = (t)cimg::_pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h;
philpem@5 27250 cimg_forY(U,j) { const t y = U(nm,j), z = U(i,j); U(nm,j) = y*c+z*s; U(i,j) = z*c-y*s; }
philpem@5 27251 }
philpem@5 27252 }
philpem@5 27253 const t z = S[k];
philpem@5 27254 if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; }
philpem@5 27255 nm = k-1;
philpem@5 27256 t x = S[l], y = S[nm];
philpem@5 27257 g = rv1[nm]; h = rv1[k];
philpem@5 27258 f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y);
philpem@5 27259 g = (t)cimg::_pythagore(f,1.0);
philpem@5 27260 f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x;
philpem@5 27261 c = s = 1;
philpem@5 27262 for (int j=l; j<=nm; ++j) {
philpem@5 27263 const int i = j+1;
philpem@5 27264 g = rv1[i]; h = s*g; g = c*g;
philpem@5 27265 t y = S[i];
philpem@5 27266 t z = (t)cimg::_pythagore(f,h);
philpem@5 27267 rv1[j] = z; c = f/z; s = h/z;
philpem@5 27268 f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c;
philpem@5 27269 cimg_forX(U,jj) { const t x = V(j,jj), z = V(i,jj); V(j,jj) = x*c+z*s; V(i,jj) = z*c-x*s; }
philpem@5 27270 z = (t)cimg::_pythagore(f,h); S[j] = z;
philpem@5 27271 if (z) { z = 1/z; c = f*z; s = h*z; }
philpem@5 27272 f = c*g+s*y; x = c*y-s*g;
philpem@5 27273 { cimg_forY(U,jj) { const t y = U(j,jj); z = U(i,jj); U(j,jj) = y*c+z*s; U(i,jj) = z*c-y*s; }}
philpem@5 27274 }
philpem@5 27275 rv1[l] = 0; rv1[k]=f; S[k]=x;
philpem@5 27276 }
philpem@5 27277 }
philpem@5 27278
philpem@5 27279 if (sorting) {
philpem@5 27280 CImg<intT> permutations(width);
philpem@5 27281 CImg<t> tmp(width);
philpem@5 27282 S.sort(permutations,false);
philpem@5 27283 cimg_forY(U,k) {
philpem@5 27284 cimg_forX(permutations,x) tmp(x) = U(permutations(x),k);
philpem@5 27285 cimg_std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width);
philpem@5 27286 }
philpem@5 27287 { cimg_forY(V,k) {
philpem@5 27288 cimg_forX(permutations,x) tmp(x) = V(permutations(x),k);
philpem@5 27289 cimg_std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width);
philpem@5 27290 }}
philpem@5 27291 }
philpem@5 27292 }
philpem@5 27293 return *this;
philpem@5 27294 }
philpem@5 27295
philpem@5 27296 //! Compute the SVD of a general matrix.
philpem@5 27297 template<typename t>
philpem@5 27298 const CImg<T>& SVD(CImgList<t>& USV) const {
philpem@5 27299 if (USV.size<3) USV.assign(3);
philpem@5 27300 return SVD(USV[0],USV[1],USV[2]);
philpem@5 27301 }
philpem@5 27302
philpem@5 27303 //! Compute the SVD of a general matrix.
philpem@5 27304 CImgList<Tfloat> get_SVD(const bool sorting=true) const {
philpem@5 27305 CImgList<Tfloat> res(3);
philpem@5 27306 SVD(res[0],res[1],res[2],sorting);
philpem@5 27307 return res;
philpem@5 27308 }
philpem@5 27309
philpem@5 27310 // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies)
philpem@5 27311 template<typename t>
philpem@5 27312 CImg<T>& _LU(CImg<t>& indx, bool& d) {
philpem@5 27313 const int N = dimx();
philpem@5 27314 int imax = 0;
philpem@5 27315 CImg<Tfloat> vv(N);
philpem@5 27316 indx.assign(N);
philpem@5 27317 d = true;
philpem@5 27318 cimg_forX(*this,i) {
philpem@5 27319 Tfloat vmax = 0;
philpem@5 27320 cimg_forX(*this,j) {
philpem@5 27321 const Tfloat tmp = cimg::abs((*this)(j,i));
philpem@5 27322 if (tmp>vmax) vmax = tmp;
philpem@5 27323 }
philpem@5 27324 if (vmax==0) { indx.fill(0); return fill(0); }
philpem@5 27325 vv[i] = 1/vmax;
philpem@5 27326 }
philpem@5 27327 cimg_forX(*this,j) {
philpem@5 27328 for (int i=0; i<j; ++i) {
philpem@5 27329 Tfloat sum=(*this)(j,i);
philpem@5 27330 for (int k=0; k<i; ++k) sum-=(*this)(k,i)*(*this)(j,k);
philpem@5 27331 (*this)(j,i) = (T)sum;
philpem@5 27332 }
philpem@5 27333 Tfloat vmax = 0;
philpem@5 27334 { for (int i=j; i<dimx(); ++i) {
philpem@5 27335 Tfloat sum=(*this)(j,i);
philpem@5 27336 for (int k=0; k<j; ++k) sum-=(*this)(k,i)*(*this)(j,k);
philpem@5 27337 (*this)(j,i) = (T)sum;
philpem@5 27338 const Tfloat tmp = vv[i]*cimg::abs(sum);
philpem@5 27339 if (tmp>=vmax) { vmax=tmp; imax=i; }
philpem@5 27340 }}
philpem@5 27341 if (j!=imax) {
philpem@5 27342 cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j));
philpem@5 27343 d =!d;
philpem@5 27344 vv[imax] = vv[j];
philpem@5 27345 }
philpem@5 27346 indx[j] = (t)imax;
philpem@5 27347 if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20;
philpem@5 27348 if (j<N) {
philpem@5 27349 const Tfloat tmp = 1/(Tfloat)(*this)(j,j);
philpem@5 27350 for (int i=j+1; i<N; ++i) (*this)(j,i) = (T)((*this)(j,i)*tmp);
philpem@5 27351 }
philpem@5 27352 }
philpem@5 27353 return *this;
philpem@5 27354 }
philpem@5 27355
philpem@5 27356 //! Compute the eigenvalues and eigenvectors of a matrix.
philpem@5 27357 template<typename t>
philpem@5 27358 const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
philpem@5 27359 if (is_empty()) { val.assign(); vec.assign(); }
philpem@5 27360 else {
philpem@5 27361 if (width!=height || depth>1 || dim>1)
philpem@5 27362 throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
philpem@5 27363 pixel_type(),width,height,depth,dim,data);
philpem@5 27364 if (val.size()<width) val.assign(1,width);
philpem@5 27365 if (vec.size()<width*width) vec.assign(width,width);
philpem@5 27366 switch (width) {
philpem@5 27367 case 1 : { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break;
philpem@5 27368 case 2 : {
philpem@5 27369 const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d;
philpem@5 27370 double f = e*e-4*(a*d-b*c);
philpem@5 27371 if (f<0)
philpem@5 27372 cimg::warn("CImg<%s>::eigen() : Complex eigenvalues",
philpem@5 27373 pixel_type());
philpem@5 27374 f = cimg_std::sqrt(f);
philpem@5 27375 const double l1 = 0.5*(e-f), l2 = 0.5*(e+f);
philpem@5 27376 const double theta1 = cimg_std::atan2(l2-a,b), theta2 = cimg_std::atan2(l1-a,b);
philpem@5 27377 val[0]=(t)l2;
philpem@5 27378 val[1]=(t)l1;
philpem@5 27379 vec(0,0) = (t)cimg_std::cos(theta1);
philpem@5 27380 vec(0,1) = (t)cimg_std::sin(theta1);
philpem@5 27381 vec(1,0) = (t)cimg_std::cos(theta2);
philpem@5 27382 vec(1,1) = (t)cimg_std::sin(theta2);
philpem@5 27383 } break;
philpem@5 27384 default :
philpem@5 27385 throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited"
philpem@5 27386 "to 2x2 matrices (given is %ux%u)",
philpem@5 27387 pixel_type(),width,height);
philpem@5 27388 }
philpem@5 27389 }
philpem@5 27390 return *this;
philpem@5 27391 }
philpem@5 27392
philpem@5 27393 //! Compute the eigenvalues and eigenvectors of a matrix.
philpem@5 27394 CImgList<Tfloat> get_eigen() const {
philpem@5 27395 CImgList<Tfloat> res(2);
philpem@5 27396 eigen(res[0],res[1]);
philpem@5 27397 return res;
philpem@5 27398 }
philpem@5 27399
philpem@5 27400 //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
philpem@5 27401 template<typename t>
philpem@5 27402 const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& vec) const {
philpem@5 27403 if (is_empty()) { val.assign(); vec.assign(); }
philpem@5 27404 else {
philpem@5 27405 #ifdef cimg_use_lapack
philpem@5 27406 char JOB = 'V', UPLO = 'U';
philpem@5 27407 int N = width, LWORK = 4*N, INFO;
philpem@5 27408 Tfloat
philpem@5 27409 *lapA = new Tfloat[N*N],
philpem@5 27410 *lapW = new Tfloat[N],
philpem@5 27411 *WORK = new Tfloat[LWORK];
philpem@5 27412 cimg_forXY(*this,k,l) lapA[k*N+l] = (Tfloat)((*this)(k,l));
philpem@5 27413 cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO);
philpem@5 27414 if (INFO)
philpem@5 27415 cimg::warn("CImg<%s>::symmetric_eigen() : LAPACK library function dsyev_() returned error code %d.",
philpem@5 27416 pixel_type(),INFO);
philpem@5 27417 val.assign(1,N);
philpem@5 27418 vec.assign(N,N);
philpem@5 27419 if (!INFO) {
philpem@5 27420 cimg_forY(val,i) val(i) = (T)lapW[N-1-i];
philpem@5 27421 cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N-1-k)*N+l]);
philpem@5 27422 } else { val.fill(0); vec.fill(0); }
philpem@5 27423 delete[] lapA; delete[] lapW; delete[] WORK;
philpem@5 27424 #else
philpem@5 27425 if (width!=height || depth>1 || dim>1)
philpem@5 27426 throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.",
philpem@5 27427 pixel_type(),width,height,depth,dim,data);
philpem@5 27428 val.assign(1,width);
philpem@5 27429 if (vec.data) vec.assign(width,width);
philpem@5 27430 if (width<3) return eigen(val,vec);
philpem@5 27431 CImg<t> V(width,width);
philpem@5 27432 SVD(vec,val,V,false);
philpem@5 27433 bool ambiguous = false;
philpem@5 27434 float eig = 0;
philpem@5 27435 cimg_forY(val,p) { // check for ambiguous cases.
philpem@5 27436 if (val[p]>eig) eig = (float)val[p];
philpem@5 27437 t scal = 0;
philpem@5 27438 cimg_forY(vec,y) scal+=vec(p,y)*V(p,y);
philpem@5 27439 if (cimg::abs(scal)<0.9f) ambiguous = true;
philpem@5 27440 if (scal<0) val[p] = -val[p];
philpem@5 27441 }
philpem@5 27442 if (ambiguous) {
philpem@5 27443 (eig*=2)++;
philpem@5 27444 SVD(vec,val,V,false,40,eig);
philpem@5 27445 val-=eig;
philpem@5 27446 }
philpem@5 27447 CImg<intT> permutations(width); // sort eigenvalues in decreasing order
philpem@5 27448 CImg<t> tmp(width);
philpem@5 27449 val.sort(permutations,false);
philpem@5 27450 cimg_forY(vec,k) {
philpem@5 27451 cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k);
philpem@5 27452 cimg_std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width);
philpem@5 27453 }
philpem@5 27454 #endif
philpem@5 27455 }
philpem@5 27456 return *this;
philpem@5 27457 }
philpem@5 27458
philpem@5 27459 //! Compute the eigenvalues and eigenvectors of a symmetric matrix.
philpem@5 27460 CImgList<Tfloat> get_symmetric_eigen() const {
philpem@5 27461 CImgList<Tfloat> res(2);
philpem@5 27462 symmetric_eigen(res[0],res[1]);
philpem@5 27463 return res;
philpem@5 27464 }
philpem@5 27465
philpem@5 27466 //@}
philpem@5 27467 //-------------------
philpem@5 27468 //
philpem@5 27469 //! \name Display
philpem@5 27470 //@{
philpem@5 27471 //-------------------
philpem@5 27472
philpem@5 27473 //! Display an image into a CImgDisplay window.
philpem@5 27474 const CImg<T>& display(CImgDisplay& disp) const {
philpem@5 27475 disp.display(*this);
philpem@5 27476 return *this;
philpem@5 27477 }
philpem@5 27478
philpem@5 27479 //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
philpem@5 27480 const CImg<T>& display(CImgDisplay &disp, const bool display_info) const {
philpem@5 27481 return _display(disp,0,display_info);
philpem@5 27482 }
philpem@5 27483
philpem@5 27484 //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n
philpem@5 27485 const CImg<T>& display(const char *const title=0, const bool display_info=true) const {
philpem@5 27486 CImgDisplay disp;
philpem@5 27487 return _display(disp,title,display_info);
philpem@5 27488 }
philpem@5 27489
philpem@5 27490 const CImg<T>& _display(CImgDisplay &disp, const char *const title, const bool display_info) const {
philpem@5 27491 if (is_empty())
philpem@5 27492 throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 27493 pixel_type(),width,height,depth,dim,data);
philpem@5 27494 unsigned int oldw = 0, oldh = 0, XYZ[3], key = 0, mkey = 0;
philpem@5 27495 int x0 = 0, y0 = 0, z0 = 0, x1 = dimx()-1, y1 = dimy()-1, z1 = dimz()-1;
philpem@5 27496 float frametiming = 5;
philpem@5 27497
philpem@5 27498 char ntitle[256] = { 0 };
philpem@5 27499 if (!disp) {
philpem@5 27500 if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
philpem@5 27501 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
philpem@5 27502 }
philpem@5 27503 cimg_std::strncpy(ntitle,disp.title,255);
philpem@5 27504 if (display_info) print(ntitle);
philpem@5 27505
philpem@5 27506 CImg<T> zoom;
philpem@5 27507 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
philpem@5 27508 if (reset_view) {
philpem@5 27509 XYZ[0] = (x0 + x1)/2; XYZ[1] = (y0 + y1)/2; XYZ[2] = (z0 + z1)/2;
philpem@5 27510 x0 = 0; y0 = 0; z0 = 0; x1 = width-1; y1 = height-1; z1 = depth-1;
philpem@5 27511 oldw = disp.width; oldh = disp.height;
philpem@5 27512 reset_view = false;
philpem@5 27513 }
philpem@5 27514 if (!x0 && !y0 && !z0 && x1==dimx()-1 && y1==dimy()-1 && z1==dimz()-1) zoom.assign();
philpem@5 27515 else zoom = get_crop(x0,y0,z0,x1,y1,z1);
philpem@5 27516
philpem@5 27517 const unsigned int
philpem@5 27518 dx = 1 + x1 - x0, dy = 1 + y1 - y0, dz = 1 + z1 - z0,
philpem@5 27519 tw = dx + (dz>1?dz:0), th = dy + (dz>1?dz:0);
philpem@5 27520 if (resize_disp) {
philpem@5 27521 const unsigned int
philpem@5 27522 ttw = tw*disp.width/oldw, tth = th*disp.height/oldh,
philpem@5 27523 dM = cimg::max(ttw,tth), diM = cimg::max(disp.width,disp.height),
philpem@5 27524 imgw = cimg::max(16U,ttw*diM/dM), imgh = cimg::max(16U,tth*diM/dM);
philpem@5 27525 disp.normalscreen().resize(cimg_fitscreen(imgw,imgh,1),false);
philpem@5 27526 resize_disp = false;
philpem@5 27527 }
philpem@5 27528 oldw = tw; oldh = th;
philpem@5 27529
philpem@5 27530 bool
philpem@5 27531 go_up = false, go_down = false, go_left = false, go_right = false,
philpem@5 27532 go_inc = false, go_dec = false, go_in = false, go_out = false,
philpem@5 27533 go_in_center = false;
philpem@5 27534 const CImg<T>& visu = zoom?zoom:*this;
philpem@5 27535 const CImg<intT> selection = visu._get_select(disp,0,2,XYZ,0,x0,y0,z0);
philpem@5 27536 if (disp.wheel) {
philpem@5 27537 if (disp.is_keyCTRLLEFT) { if (!mkey || mkey==1) go_out = !(go_in = disp.wheel>0); go_in_center = false; mkey = 1; }
philpem@5 27538 else if (disp.is_keySHIFTLEFT) { if (!mkey || mkey==2) go_right = !(go_left = disp.wheel>0); mkey = 2; }
philpem@5 27539 else if (disp.is_keyALT || depth==1) { if (!mkey || mkey==3) go_down = !(go_up = disp.wheel>0); mkey = 3; }
philpem@5 27540 else mkey = 0;
philpem@5 27541 disp.wheel = 0;
philpem@5 27542 } else mkey = 0;
philpem@5 27543 const int
philpem@5 27544 sx0 = selection(0), sy0 = selection(1), sz0 = selection(2),
philpem@5 27545 sx1 = selection(3), sy1 = selection(4), sz1 = selection(5);
philpem@5 27546 if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) {
philpem@5 27547 x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; x0+=sx0; y0+=sy0; z0+=sz0;
philpem@5 27548 if (sx0==sx1 && sy0==sy1 && sz0==sz1) reset_view = true;
philpem@5 27549 resize_disp = true;
philpem@5 27550 } else switch (key = disp.key) {
philpem@5 27551 case 0 : case cimg::keyCTRLLEFT : case cimg::keyPAD5 : case cimg::keySHIFTLEFT : case cimg::keyALT : disp.key = key = 0; break;
philpem@5 27552 case cimg::keyP : if (visu.depth>1 && disp.is_keyCTRLLEFT) { // Special mode : play stack of frames
philpem@5 27553 const unsigned int
philpem@5 27554 w1 = visu.width*disp.width/(visu.width+(visu.depth>1?visu.depth:0)),
philpem@5 27555 h1 = visu.height*disp.height/(visu.height+(visu.depth>1?visu.depth:0));
philpem@5 27556 disp.resize(cimg_fitscreen(w1,h1,1),false).key = disp.wheel = key = 0;
philpem@5 27557 for (unsigned int timer = 0; !key && !disp.is_closed && !disp.button; ) {
philpem@5 27558 if (disp.is_resized) disp.resize();
philpem@5 27559 if (!timer) {
philpem@5 27560 visu.get_slice(XYZ[2]).display(disp.set_title("%s | z=%d",ntitle,XYZ[2]));
philpem@5 27561 if (++XYZ[2]>=visu.depth) XYZ[2] = 0;
philpem@5 27562 }
philpem@5 27563 if (++timer>(unsigned int)frametiming) timer = 0;
philpem@5 27564 if (disp.wheel) { frametiming-=disp.wheel/3.0f; disp.wheel = 0; }
philpem@5 27565 switch (key = disp.key) {
philpem@5 27566 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
philpem@5 27567 case cimg::keyPAGEUP : frametiming-=0.3f; key = 0; break;
philpem@5 27568 case cimg::keyPAGEDOWN : frametiming+=0.3f; key = 0; break;
philpem@5 27569 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
philpem@5 27570 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
philpem@5 27571 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false);
philpem@5 27572 disp.key = key = 0;
philpem@5 27573 } break;
philpem@5 27574 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
philpem@5 27575 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false);
philpem@5 27576 disp.key = key = 0;
philpem@5 27577 } break;
philpem@5 27578 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
philpem@5 27579 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false);
philpem@5 27580 disp.key = key = 0;
philpem@5 27581 } break;
philpem@5 27582 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
philpem@5 27583 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen();
philpem@5 27584 disp.key = key = 0;
philpem@5 27585 } break;
philpem@5 27586 }
philpem@5 27587 frametiming = frametiming<1?1:(frametiming>39?39:frametiming);
philpem@5 27588 disp.wait(20);
philpem@5 27589 }
philpem@5 27590 const unsigned int
philpem@5 27591 w2 = (visu.width + (visu.depth>1?visu.depth:0))*disp.width/visu.width,
philpem@5 27592 h2 = (visu.height + (visu.depth>1?visu.depth:0))*disp.height/visu.height;
philpem@5 27593 disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(ntitle);
philpem@5 27594 key = disp.key = disp.button = disp.wheel = 0;
philpem@5 27595 } break;
philpem@5 27596 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
philpem@5 27597 case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break;
philpem@5 27598 case cimg::keyPADSUB : go_out = true; key = 0; break;
philpem@5 27599 case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break;
philpem@5 27600 case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break;
philpem@5 27601 case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break;
philpem@5 27602 case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break;
philpem@5 27603 case cimg::keyPAD7 : go_up = go_left = true; key = 0; break;
philpem@5 27604 case cimg::keyPAD9 : go_up = go_right = true; key = 0; break;
philpem@5 27605 case cimg::keyPAD1 : go_down = go_left = true; key = 0; break;
philpem@5 27606 case cimg::keyPAD3 : go_down = go_right = true; key = 0; break;
philpem@5 27607 case cimg::keyPAGEUP : go_inc = true; key = 0; break;
philpem@5 27608 case cimg::keyPAGEDOWN : go_dec = true; key = 0; break;
philpem@5 27609 }
philpem@5 27610 if (go_in) {
philpem@5 27611 const int
philpem@5 27612 mx = go_in_center?disp.dimx()/2:disp.mouse_x,
philpem@5 27613 my = go_in_center?disp.dimy()/2:disp.mouse_y,
philpem@5 27614 mX = mx*(width+(depth>1?depth:0))/disp.width,
philpem@5 27615 mY = my*(height+(depth>1?depth:0))/disp.height;
philpem@5 27616 int X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
philpem@5 27617 if (mX<dimx() && mY<dimy()) { X = x0 + mX*(1+x1-x0)/width; Y = y0 + mY*(1+y1-y0)/height; Z = XYZ[2]; }
philpem@5 27618 if (mX<dimx() && mY>=dimy()) { X = x0 + mX*(1+x1-x0)/width; Z = z0 + (mY-height)*(1+z1-z0)/depth; Y = XYZ[1]; }
philpem@5 27619 if (mX>=dimx() && mY<dimy()) { Y = y0 + mY*(1+y1-y0)/height; Z = z0 + (mX-width)*(1+z1-z0)/depth; X = XYZ[0]; }
philpem@5 27620 if (x1-x0>4) { x0 = X - 7*(X-x0)/8; x1 = X + 7*(x1-X)/8; }
philpem@5 27621 if (y1-y0>4) { y0 = Y - 7*(Y-y0)/8; y1 = Y + 7*(y1-Y)/8; }
philpem@5 27622 if (z1-z0>4) { z0 = Z - 7*(Z-z0)/8; z1 = Z + 7*(z1-Z)/8; }
philpem@5 27623 }
philpem@5 27624 if (go_out) {
philpem@5 27625 const int
philpem@5 27626 deltax = (x1-x0)/8, deltay = (y1-y0)/8, deltaz = (z1-z0)/8,
philpem@5 27627 ndeltax = deltax?deltax:(width>1?1:0),
philpem@5 27628 ndeltay = deltay?deltay:(height>1?1:0),
philpem@5 27629 ndeltaz = deltaz?deltaz:(depth>1?1:0);
philpem@5 27630 x0-=ndeltax; y0-=ndeltay; z0-=ndeltaz;
philpem@5 27631 x1+=ndeltax; y1+=ndeltay; z1+=ndeltaz;
philpem@5 27632 if (x0<0) { x1-=x0; x0 = 0; if (x1>=dimx()) x1 = dimx()-1; }
philpem@5 27633 if (y0<0) { y1-=y0; y0 = 0; if (y1>=dimy()) y1 = dimy()-1; }
philpem@5 27634 if (z0<0) { z1-=z0; z0 = 0; if (z1>=dimz()) z1 = dimz()-1; }
philpem@5 27635 if (x1>=dimx()) { x0-=(x1-dimx()+1); x1 = dimx()-1; if (x0<0) x0 = 0; }
philpem@5 27636 if (y1>=dimy()) { y0-=(y1-dimy()+1); y1 = dimy()-1; if (y0<0) y0 = 0; }
philpem@5 27637 if (z1>=dimz()) { z0-=(z1-dimz()+1); z1 = dimz()-1; if (z0<0) z0 = 0; }
philpem@5 27638 }
philpem@5 27639 if (go_left) {
philpem@5 27640 const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
philpem@5 27641 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
philpem@5 27642 else { x1-=x0; x0 = 0; }
philpem@5 27643 }
philpem@5 27644 if (go_right) {
philpem@5 27645 const int delta = (x1-x0)/5, ndelta = delta?delta:(width>1?1:0);
philpem@5 27646 if (x1+ndelta<dimx()) { x0+=ndelta; x1+=ndelta; }
philpem@5 27647 else { x0+=(dimx()-1-x1); x1 = dimx()-1; }
philpem@5 27648 }
philpem@5 27649 if (go_up) {
philpem@5 27650 const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
philpem@5 27651 if (y0-ndelta>=0) { y0-=ndelta; y1-=ndelta; }
philpem@5 27652 else { y1-=y0; y0 = 0; }
philpem@5 27653 }
philpem@5 27654 if (go_down) {
philpem@5 27655 const int delta = (y1-y0)/5, ndelta = delta?delta:(height>1?1:0);
philpem@5 27656 if (y1+ndelta<dimy()) { y0+=ndelta; y1+=ndelta; }
philpem@5 27657 else { y0+=(dimy()-1-y1); y1 = dimy()-1; }
philpem@5 27658 }
philpem@5 27659 if (go_inc) {
philpem@5 27660 const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
philpem@5 27661 if (z0-ndelta>=0) { z0-=ndelta; z1-=ndelta; }
philpem@5 27662 else { z1-=z0; z0 = 0; }
philpem@5 27663 }
philpem@5 27664 if (go_dec) {
philpem@5 27665 const int delta = (z1-z0)/5, ndelta = delta?delta:(depth>1?1:0);
philpem@5 27666 if (z1+ndelta<dimz()) { z0+=ndelta; z1+=ndelta; }
philpem@5 27667 else { z0+=(depth-1-z1); z1 = depth-1; }
philpem@5 27668 }
philpem@5 27669 }
philpem@5 27670 disp.key = key;
philpem@5 27671 return *this;
philpem@5 27672 }
philpem@5 27673
philpem@5 27674 //! Simple interface to select a shape from an image.
philpem@5 27675 /**
philpem@5 27676 \param selection Array of 6 values containing the selection result
philpem@5 27677 \param coords_type Determine shape type to select (0=point, 1=vector, 2=rectangle, 3=circle)
philpem@5 27678 \param disp Display window used to make the selection
philpem@5 27679 \param XYZ Initial XYZ position (for volumetric images only)
philpem@5 27680 \param color Color of the shape selector.
philpem@5 27681 **/
philpem@5 27682 CImg<T>& select(CImgDisplay &disp,
philpem@5 27683 const int select_type=2, unsigned int *const XYZ=0,
philpem@5 27684 const unsigned char *const color=0) {
philpem@5 27685 return get_select(disp,select_type,XYZ,color).transfer_to(*this);
philpem@5 27686 }
philpem@5 27687
philpem@5 27688 //! Simple interface to select a shape from an image.
philpem@5 27689 CImg<T>& select(const char *const title,
philpem@5 27690 const int select_type=2, unsigned int *const XYZ=0,
philpem@5 27691 const unsigned char *const color=0) {
philpem@5 27692 return get_select(title,select_type,XYZ,color).transfer_to(*this);
philpem@5 27693 }
philpem@5 27694
philpem@5 27695 //! Simple interface to select a shape from an image.
philpem@5 27696 CImg<intT> get_select(CImgDisplay &disp,
philpem@5 27697 const int select_type=2, unsigned int *const XYZ=0,
philpem@5 27698 const unsigned char *const color=0) const {
philpem@5 27699 return _get_select(disp,0,select_type,XYZ,color,0,0,0);
philpem@5 27700 }
philpem@5 27701
philpem@5 27702 //! Simple interface to select a shape from an image.
philpem@5 27703 CImg<intT> get_select(const char *const title,
philpem@5 27704 const int select_type=2, unsigned int *const XYZ=0,
philpem@5 27705 const unsigned char *const color=0) const {
philpem@5 27706 CImgDisplay disp;
philpem@5 27707 return _get_select(disp,title,select_type,XYZ,color,0,0,0);
philpem@5 27708 }
philpem@5 27709
philpem@5 27710 CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
philpem@5 27711 const int coords_type, unsigned int *const XYZ,
philpem@5 27712 const unsigned char *const color,
philpem@5 27713 const int origX, const int origY, const int origZ) const {
philpem@5 27714 if (is_empty())
philpem@5 27715 throw CImgInstanceException("CImg<%s>::select() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 27716 pixel_type(),width,height,depth,dim,data);
philpem@5 27717 if (!disp) {
philpem@5 27718 char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
philpem@5 27719 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
philpem@5 27720 }
philpem@5 27721
philpem@5 27722 const unsigned int
philpem@5 27723 old_normalization = disp.normalization,
philpem@5 27724 hatch = 0x55555555;
philpem@5 27725
philpem@5 27726 bool old_is_resized = disp.is_resized;
philpem@5 27727 disp.normalization = 0;
philpem@5 27728 disp.show().key = 0;
philpem@5 27729
philpem@5 27730 unsigned char foreground_color[] = { 255,255,105 }, background_color[] = { 0,0,0 };
philpem@5 27731 if (color) cimg_std::memcpy(foreground_color,color,sizeof(unsigned char)*cimg::min(3,dimv()));
philpem@5 27732
philpem@5 27733 int area = 0, clicked_area = 0, phase = 0,
philpem@5 27734 X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth),
philpem@5 27735 X1 =-1, Y1 = -1, Z1 = -1,
philpem@5 27736 X = -1, Y = -1, Z = -1,
philpem@5 27737 oX = X, oY = Y, oZ = Z;
philpem@5 27738 unsigned int old_button = 0, key = 0;
philpem@5 27739
philpem@5 27740 bool shape_selected = false, text_down = false;
philpem@5 27741 CImg<ucharT> visu, visu0;
philpem@5 27742 char text[1024] = { 0 };
philpem@5 27743
philpem@5 27744 while (!key && !disp.is_closed && !shape_selected) {
philpem@5 27745
philpem@5 27746 // Handle mouse motion and selection
philpem@5 27747 oX = X; oY = Y; oZ = Z;
philpem@5 27748 int mx = disp.mouse_x, my = disp.mouse_y;
philpem@5 27749 const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height;
philpem@5 27750
philpem@5 27751 area = 0;
philpem@5 27752 if (mX<dimx() && mY<dimy()) { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; }
philpem@5 27753 if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; }
philpem@5 27754 if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; }
philpem@5 27755
philpem@5 27756 switch (key = disp.key) {
philpem@5 27757 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
philpem@5 27758 case cimg::keyPAGEUP : if (disp.is_keyCTRLLEFT) { ++disp.wheel; key = 0; } break;
philpem@5 27759 case cimg::keyPAGEDOWN : if (disp.is_keyCTRLLEFT) { --disp.wheel; key = 0; } break;
philpem@5 27760 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
philpem@5 27761 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
philpem@5 27762 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
philpem@5 27763 disp.key = key = 0;
philpem@5 27764 } break;
philpem@5 27765 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
philpem@5 27766 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
philpem@5 27767 disp.key = key = 0; visu0.assign();
philpem@5 27768 } break;
philpem@5 27769 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
philpem@5 27770 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
philpem@5 27771 disp.key = key = 0; visu0.assign();
philpem@5 27772 } break;
philpem@5 27773 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
philpem@5 27774 disp.resize(disp.screen_dimx(),disp.screen_dimy(),false).toggle_fullscreen().is_resized = true;
philpem@5 27775 disp.key = key = 0; visu0.assign();
philpem@5 27776 } break;
philpem@5 27777 case cimg::keyS : if (disp.is_keyCTRLLEFT) {
philpem@5 27778 static unsigned int snap_number = 0;
philpem@5 27779 char filename[32] = { 0 };
philpem@5 27780 cimg_std::FILE *file;
philpem@5 27781 do {
philpem@5 27782 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
philpem@5 27783 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 27784 } while (file);
philpem@5 27785 if (visu0) {
philpem@5 27786 visu.draw_text(2,2,"Saving snapshot...",foreground_color,background_color,0.8f,11).display(disp);
philpem@5 27787 visu0.save(filename);
philpem@5 27788 visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
philpem@5 27789 }
philpem@5 27790 disp.key = key = 0;
philpem@5 27791 } break;
philpem@5 27792 case cimg::keyO : if (disp.is_keyCTRLLEFT) {
philpem@5 27793 static unsigned int snap_number = 0;
philpem@5 27794 char filename[32] = { 0 };
philpem@5 27795 cimg_std::FILE *file;
philpem@5 27796 do {
philpem@5 27797 cimg_std::sprintf(filename,"CImg_%.4u.cimg",snap_number++);
philpem@5 27798 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 27799 } while (file);
philpem@5 27800 visu.draw_text(2,2,"Saving instance...",foreground_color,background_color,0.8f,11).display(disp);
philpem@5 27801 save(filename);
philpem@5 27802 visu.draw_text(2,2,"Instance '%s' saved.",foreground_color,background_color,0.8f,11,filename).display(disp);
philpem@5 27803 disp.key = key = 0;
philpem@5 27804 } break;
philpem@5 27805 }
philpem@5 27806
philpem@5 27807 if (!area) mx = my = X = Y = Z = -1;
philpem@5 27808 else {
philpem@5 27809 if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; }
philpem@5 27810 if (!(disp.button&1) && phase>=2) {
philpem@5 27811 switch (clicked_area) {
philpem@5 27812 case 1 : Z1 = Z; break;
philpem@5 27813 case 2 : Y1 = Y; break;
philpem@5 27814 case 3 : X1 = X; break;
philpem@5 27815 }
philpem@5 27816 }
philpem@5 27817 if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } }
philpem@5 27818 if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); }
philpem@5 27819 if (disp.wheel) {
philpem@5 27820 if (depth>1 && !disp.is_keyCTRLLEFT && !disp.is_keySHIFTLEFT && !disp.is_keyALT) {
philpem@5 27821 switch (area) {
philpem@5 27822 case 1 : if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break;
philpem@5 27823 case 2 : if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break;
philpem@5 27824 case 3 : if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break;
philpem@5 27825 }
philpem@5 27826 disp.wheel = 0;
philpem@5 27827 } else key = ~0U;
philpem@5 27828 }
philpem@5 27829 if ((disp.button&1)!=old_button) {
philpem@5 27830 switch (phase++) {
philpem@5 27831 case 0 : X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break;
philpem@5 27832 case 1 : X1 = X; Y1 = Y; Z1 = Z; break;
philpem@5 27833 }
philpem@5 27834 old_button = disp.button&1;
philpem@5 27835 }
philpem@5 27836 if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign();
philpem@5 27837 }
philpem@5 27838
philpem@5 27839 if (phase) {
philpem@5 27840 if (!coords_type) shape_selected = phase?true:false;
philpem@5 27841 else {
philpem@5 27842 if (depth>1) shape_selected = (phase==3)?true:false;
philpem@5 27843 else shape_selected = (phase==2)?true:false;
philpem@5 27844 }
philpem@5 27845 }
philpem@5 27846
philpem@5 27847 if (X0<0) X0 = 0; if (X0>=dimx()) X0 = dimx()-1; if (Y0<0) Y0 = 0; if (Y0>=dimy()) Y0 = dimy()-1;
philpem@5 27848 if (Z0<0) Z0 = 0; if (Z0>=dimz()) Z0 = dimz()-1;
philpem@5 27849 if (X1<1) X1 = 0; if (X1>=dimx()) X1 = dimx()-1; if (Y1<0) Y1 = 0; if (Y1>=dimy()) Y1 = dimy()-1;
philpem@5 27850 if (Z1<0) Z1 = 0; if (Z1>=dimz()) Z1 = dimz()-1;
philpem@5 27851
philpem@5 27852 // Draw visualization image on the display
philpem@5 27853 if (oX!=X || oY!=Y || oZ!=Z || !visu0) {
philpem@5 27854 if (!visu0) {
philpem@5 27855 CImg<Tuchar> tmp, tmp0;
philpem@5 27856 if (depth!=1) {
philpem@5 27857 tmp0 = (!phase)?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1);
philpem@5 27858 tmp = tmp0.get_channels(0,cimg::min(2U,dim-1));
philpem@5 27859 } else tmp = get_channels(0,cimg::min(2U,dim-1));
philpem@5 27860 switch (old_normalization) {
philpem@5 27861 case 0 : visu0 = tmp; break;
philpem@5 27862 case 3 :
philpem@5 27863 if (cimg::type<T>::is_float()) visu0 = tmp.normalize(0,(T)255);
philpem@5 27864 else {
philpem@5 27865 const float m = (float)cimg::type<T>::min(), M = (float)cimg::type<T>::max();
philpem@5 27866 visu0.assign(tmp.width,tmp.height,1,tmp.dim);
philpem@5 27867 unsigned char *ptrd = visu0.end();
philpem@5 27868 cimg_for(tmp,ptrs,Tuchar) *(--ptrd) = (unsigned char)((*ptrs-m)*255.0f/(M-m));
philpem@5 27869 } break;
philpem@5 27870 default : visu0 = tmp.normalize(0,255);
philpem@5 27871 }
philpem@5 27872 visu0.resize(disp);
philpem@5 27873 }
philpem@5 27874 visu = visu0;
philpem@5 27875 if (!color) {
philpem@5 27876 if (visu.mean()<200) {
philpem@5 27877 foreground_color[0] = foreground_color[1] = foreground_color[2] = 255;
philpem@5 27878 background_color[0] = background_color[1] = background_color[2] = 0;
philpem@5 27879 } else {
philpem@5 27880 foreground_color[0] = foreground_color[1] = foreground_color[2] = 0;
philpem@5 27881 background_color[0] = background_color[1] = background_color[2] = 255;
philpem@5 27882 }
philpem@5 27883 }
philpem@5 27884
philpem@5 27885 const int d = (depth>1)?depth:0;
philpem@5 27886 if (phase) switch (coords_type) {
philpem@5 27887 case 1 : {
philpem@5 27888 const int
philpem@5 27889 x0 = (int)((X0+0.5f)*disp.width/(width+d)),
philpem@5 27890 y0 = (int)((Y0+0.5f)*disp.height/(height+d)),
philpem@5 27891 x1 = (int)((X1+0.5f)*disp.width/(width+d)),
philpem@5 27892 y1 = (int)((Y1+0.5f)*disp.height/(height+d));
philpem@5 27893 visu.draw_arrow(x0,y0,x1,y1,foreground_color,0.6f,30,5,hatch);
philpem@5 27894 if (d) {
philpem@5 27895 const int
philpem@5 27896 zx0 = (int)((width+Z0+0.5f)*disp.width/(width+d)),
philpem@5 27897 zx1 = (int)((width+Z1+0.5f)*disp.width/(width+d)),
philpem@5 27898 zy0 = (int)((height+Z0+0.5f)*disp.height/(height+d)),
philpem@5 27899 zy1 = (int)((height+Z1+0.5f)*disp.height/(height+d));
philpem@5 27900 visu.draw_arrow(zx0,y0,zx1,y1,foreground_color,0.6f,30,5,hatch).
philpem@5 27901 draw_arrow(x0,zy0,x1,zy1,foreground_color,0.6f,30,5,hatch);
philpem@5 27902 }
philpem@5 27903 } break;
philpem@5 27904 case 2 : {
philpem@5 27905 const int
philpem@5 27906 x0 = (X0<X1?X0:X1)*disp.width/(width+d), y0 = (Y0<Y1?Y0:Y1)*disp.height/(height+d),
philpem@5 27907 x1 = ((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, y1 = ((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1;
philpem@5 27908 visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.2f).draw_rectangle(x0,y0,x1,y1,foreground_color,0.6f,hatch);
philpem@5 27909 if (d) {
philpem@5 27910 const int
philpem@5 27911 zx0 = (int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)),
philpem@5 27912 zy0 = (int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)),
philpem@5 27913 zx1 = (int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1,
philpem@5 27914 zy1 = (int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1;
philpem@5 27915 visu.draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.2f).draw_rectangle(zx0,y0,zx1,y1,foreground_color,0.6f,hatch);
philpem@5 27916 visu.draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.2f).draw_rectangle(x0,zy0,x1,zy1,foreground_color,0.6f,hatch);
philpem@5 27917 }
philpem@5 27918 } break;
philpem@5 27919 case 3 : {
philpem@5 27920 const int
philpem@5 27921 x0 = X0*disp.width/(width+d),
philpem@5 27922 y0 = Y0*disp.height/(height+d),
philpem@5 27923 x1 = X1*disp.width/(width+d)-1,
philpem@5 27924 y1 = Y1*disp.height/(height+d)-1;
philpem@5 27925 visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.2f).
philpem@5 27926 draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch);
philpem@5 27927 if (d) {
philpem@5 27928 const int
philpem@5 27929 zx0 = (int)((width+Z0)*disp.width/(width+d)),
philpem@5 27930 zy0 = (int)((height+Z0)*disp.height/(height+d)),
philpem@5 27931 zx1 = (int)((width+Z1+1)*disp.width/(width+d))-1,
philpem@5 27932 zy1 = (int)((height+Z1+1)*disp.height/(height+d))-1;
philpem@5 27933 visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.2f).
philpem@5 27934 draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1,0,foreground_color,0.6f,hatch).
philpem@5 27935 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.2f).
philpem@5 27936 draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1,0,foreground_color,0.6f,hatch);
philpem@5 27937 }
philpem@5 27938 } break;
philpem@5 27939 } else {
philpem@5 27940 const int
philpem@5 27941 x0 = X*disp.width/(width+d),
philpem@5 27942 y0 = Y*disp.height/(height+d),
philpem@5 27943 x1 = (X+1)*disp.width/(width+d)-1,
philpem@5 27944 y1 = (Y+1)*disp.height/(height+d)-1;
philpem@5 27945 if (x1-x0>=4 && y1-y0>=4) visu.draw_rectangle(x0,y0,x1,y1,foreground_color,0.4f,~0U);
philpem@5 27946 }
philpem@5 27947
philpem@5 27948 if (my<12) text_down = true;
philpem@5 27949 if (my>=visu.dimy()-11) text_down = false;
philpem@5 27950 if (!coords_type || !phase) {
philpem@5 27951 if (X>=0 && Y>=0 && Z>=0 && X<dimx() && Y<dimy() && Z<dimz()) {
philpem@5 27952 if (depth>1) cimg_std::sprintf(text,"Point (%d,%d,%d) = [ ",origX+X,origY+Y,origZ+Z);
philpem@5 27953 else cimg_std::sprintf(text,"Point (%d,%d) = [ ",origX+X,origY+Y);
philpem@5 27954 char *ctext = text + cimg::strlen(text), *const ltext = text + 512;
philpem@5 27955 for (unsigned int k=0; k<dim && ctext<ltext; ++k) {
philpem@5 27956 cimg_std::sprintf(ctext,cimg::type<T>::format(),cimg::type<T>::format((*this)(X,Y,Z,k)));
philpem@5 27957 ctext = text + cimg::strlen(text);
philpem@5 27958 *(ctext++) = ' '; *ctext = '\0';
philpem@5 27959 }
philpem@5 27960 cimg_std::sprintf(text + cimg::strlen(text),"]");
philpem@5 27961 }
philpem@5 27962 } else switch (coords_type) {
philpem@5 27963 case 1 : {
philpem@5 27964 const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), norm = cimg_std::sqrt(dX*dX+dY*dY+dZ*dZ);
philpem@5 27965 if (depth>1) cimg_std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), Norm = %g",
philpem@5 27966 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,norm);
philpem@5 27967 else cimg_std::sprintf(text,"Vect (%d,%d)-(%d,%d), Norm = %g",
philpem@5 27968 origX+X0,origY+Y0,origX+X1,origY+Y1,norm);
philpem@5 27969 } break;
philpem@5 27970 case 2 :
philpem@5 27971 if (depth>1) cimg_std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size = (%d,%d,%d)",
philpem@5 27972 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origZ+(Z0<Z1?Z0:Z1),
philpem@5 27973 origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),origZ+(Z0<Z1?Z1:Z0),
philpem@5 27974 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
philpem@5 27975 else cimg_std::sprintf(text,"Box (%d,%d)-(%d,%d), Size = (%d,%d)",
philpem@5 27976 origX+(X0<X1?X0:X1),origY+(Y0<Y1?Y0:Y1),origX+(X0<X1?X1:X0),origY+(Y0<Y1?Y1:Y0),
philpem@5 27977 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
philpem@5 27978 break;
philpem@5 27979 default :
philpem@5 27980 if (depth>1) cimg_std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii = (%d,%d,%d)",
philpem@5 27981 origX+X0,origY+Y0,origZ+Z0,origX+X1,origY+Y1,origZ+Z1,
philpem@5 27982 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1));
philpem@5 27983 else cimg_std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii = (%d,%d)",
philpem@5 27984 origX+X0,origY+Y0,origX+X1,origY+Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1));
philpem@5 27985
philpem@5 27986 }
philpem@5 27987 if (phase || (mx>=0 && my>=0)) visu.draw_text(0,text_down?visu.dimy()-11:0,text,foreground_color,background_color,0.7f,11);
philpem@5 27988 disp.display(visu).wait(25);
philpem@5 27989 } else if (!shape_selected) disp.wait();
philpem@5 27990
philpem@5 27991 if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); }
philpem@5 27992 }
philpem@5 27993
philpem@5 27994 // Return result
philpem@5 27995 CImg<intT> res(1,6,1,1,-1);
philpem@5 27996 if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; }
philpem@5 27997 if (shape_selected) {
philpem@5 27998 if (coords_type==2) {
philpem@5 27999 if (X0>X1) cimg::swap(X0,X1);
philpem@5 28000 if (Y0>Y1) cimg::swap(Y0,Y1);
philpem@5 28001 if (Z0>Z1) cimg::swap(Z0,Z1);
philpem@5 28002 }
philpem@5 28003 if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1;
philpem@5 28004 switch (coords_type) {
philpem@5 28005 case 1 :
philpem@5 28006 case 2 : res[3] = X1; res[4] = Y1; res[5] = Z1;
philpem@5 28007 default : res[0] = X0; res[1] = Y0; res[2] = Z0;
philpem@5 28008 }
philpem@5 28009 }
philpem@5 28010 disp.button = 0;
philpem@5 28011 disp.normalization = old_normalization;
philpem@5 28012 disp.is_resized = old_is_resized;
philpem@5 28013 if (key!=~0U) disp.key = key;
philpem@5 28014 return res;
philpem@5 28015 }
philpem@5 28016
philpem@5 28017 //! High-level interface for displaying a 3d object.
philpem@5 28018 template<typename tp, typename tf, typename tc, typename to>
philpem@5 28019 const CImg<T>& display_object3d(CImgDisplay& disp,
philpem@5 28020 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 28021 const CImgList<tc>& colors, const to& opacities,
philpem@5 28022 const bool centering=true,
philpem@5 28023 const int render_static=4, const int render_motion=1,
philpem@5 28024 const bool double_sided=false, const float focale=500,
philpem@5 28025 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28026 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28027 return _display_object3d(disp,0,points,points.width,primitives,colors,opacities,centering,render_static,
philpem@5 28028 render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28029 display_axes,pose_matrix);
philpem@5 28030 }
philpem@5 28031
philpem@5 28032 //! High-level interface for displaying a 3d object.
philpem@5 28033 template<typename tp, typename tf, typename tc, typename to>
philpem@5 28034 const CImg<T>& display_object3d(const char *const title,
philpem@5 28035 const CImg<tp>& points, const CImgList<tf>& primitives,
philpem@5 28036 const CImgList<tc>& colors, const to& opacities,
philpem@5 28037 const bool centering=true,
philpem@5 28038 const int render_static=4, const int render_motion=1,
philpem@5 28039 const bool double_sided=false, const float focale=500,
philpem@5 28040 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28041 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28042 CImgDisplay disp;
philpem@5 28043 return _display_object3d(disp,title,points,points.width,primitives,colors,opacities,centering,render_static,
philpem@5 28044 render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28045 display_axes,pose_matrix);
philpem@5 28046 }
philpem@5 28047
philpem@5 28048 //! High-level interface for displaying a 3d object.
philpem@5 28049 template<typename tp, typename tf, typename tc, typename to>
philpem@5 28050 const CImg<T>& display_object3d(CImgDisplay& disp,
philpem@5 28051 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 28052 const CImgList<tc>& colors, const to& opacities,
philpem@5 28053 const bool centering=true,
philpem@5 28054 const int render_static=4, const int render_motion=1,
philpem@5 28055 const bool double_sided=false, const float focale=500,
philpem@5 28056 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28057 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28058 return _display_object3d(disp,0,points,points.size,primitives,colors,opacities,centering,render_static,
philpem@5 28059 render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28060 display_axes,pose_matrix);
philpem@5 28061 }
philpem@5 28062
philpem@5 28063 //! High-level interface for displaying a 3d object.
philpem@5 28064 template<typename tp, typename tf, typename tc, typename to>
philpem@5 28065 const CImg<T>& display_object3d(const char *const title,
philpem@5 28066 const CImgList<tp>& points, const CImgList<tf>& primitives,
philpem@5 28067 const CImgList<tc>& colors, const to& opacities,
philpem@5 28068 const bool centering=true,
philpem@5 28069 const int render_static=4, const int render_motion=1,
philpem@5 28070 const bool double_sided=false, const float focale=500,
philpem@5 28071 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28072 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28073 CImgDisplay disp;
philpem@5 28074 return _display_object3d(disp,title,points,points.size,primitives,colors,opacities,centering,render_static,
philpem@5 28075 render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28076 display_axes,pose_matrix);
philpem@5 28077 }
philpem@5 28078
philpem@5 28079 //! High-level interface for displaying a 3d object.
philpem@5 28080 template<typename tp, typename tf, typename tc>
philpem@5 28081 const CImg<T>& display_object3d(CImgDisplay &disp,
philpem@5 28082 const tp& points, const CImgList<tf>& primitives,
philpem@5 28083 const CImgList<tc>& colors,
philpem@5 28084 const bool centering=true,
philpem@5 28085 const int render_static=4, const int render_motion=1,
philpem@5 28086 const bool double_sided=false, const float focale=500,
philpem@5 28087 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28088 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28089 return display_object3d(disp,points,primitives,colors,CImg<floatT>(),centering,
philpem@5 28090 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28091 display_axes,pose_matrix);
philpem@5 28092 }
philpem@5 28093
philpem@5 28094 //! High-level interface for displaying a 3d object.
philpem@5 28095 template<typename tp, typename tf, typename tc>
philpem@5 28096 const CImg<T>& display_object3d(const char *const title,
philpem@5 28097 const tp& points, const CImgList<tf>& primitives,
philpem@5 28098 const CImgList<tc>& colors,
philpem@5 28099 const bool centering=true,
philpem@5 28100 const int render_static=4, const int render_motion=1,
philpem@5 28101 const bool double_sided=false, const float focale=500,
philpem@5 28102 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28103 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28104 return display_object3d(title,points,primitives,colors,CImg<floatT>(),centering,
philpem@5 28105 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28106 display_axes,pose_matrix);
philpem@5 28107 }
philpem@5 28108
philpem@5 28109 //! High-level interface for displaying a 3d object.
philpem@5 28110 template<typename tp, typename tf>
philpem@5 28111 const CImg<T>& display_object3d(CImgDisplay &disp,
philpem@5 28112 const tp& points, const CImgList<tf>& primitives,
philpem@5 28113 const bool centering=true,
philpem@5 28114 const int render_static=4, const int render_motion=1,
philpem@5 28115 const bool double_sided=false, const float focale=500,
philpem@5 28116 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28117 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28118 return display_object3d(disp,points,primitives,CImgList<T>(),centering,
philpem@5 28119 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28120 display_axes,pose_matrix);
philpem@5 28121 }
philpem@5 28122
philpem@5 28123 //! High-level interface for displaying a 3d object.
philpem@5 28124 template<typename tp, typename tf>
philpem@5 28125 const CImg<T>& display_object3d(const char *const title,
philpem@5 28126 const tp& points, const CImgList<tf>& primitives,
philpem@5 28127 const bool centering=true,
philpem@5 28128 const int render_static=4, const int render_motion=1,
philpem@5 28129 const bool double_sided=false, const float focale=500,
philpem@5 28130 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28131 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28132 return display_object3d(title,points,primitives,CImgList<T>(),centering,
philpem@5 28133 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28134 display_axes,pose_matrix);
philpem@5 28135 }
philpem@5 28136
philpem@5 28137 //! High-level interface for displaying a 3d object.
philpem@5 28138 template<typename tp>
philpem@5 28139 const CImg<T>& display_object3d(CImgDisplay &disp,
philpem@5 28140 const tp& points,
philpem@5 28141 const bool centering=true,
philpem@5 28142 const int render_static=4, const int render_motion=1,
philpem@5 28143 const bool double_sided=false, const float focale=500,
philpem@5 28144 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28145 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28146 return display_object3d(disp,points,CImgList<uintT>(),centering,
philpem@5 28147 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28148 display_axes,pose_matrix);
philpem@5 28149 }
philpem@5 28150
philpem@5 28151 //! High-level interface for displaying a 3d object.
philpem@5 28152 template<typename tp>
philpem@5 28153 const CImg<T>& display_object3d(const char *const title,
philpem@5 28154 const tp& points,
philpem@5 28155 const bool centering=true,
philpem@5 28156 const int render_static=4, const int render_motion=1,
philpem@5 28157 const bool double_sided=false, const float focale=500,
philpem@5 28158 const float specular_light=0.2f, const float specular_shine=0.1f,
philpem@5 28159 const bool display_axes=true, float *const pose_matrix=0) const {
philpem@5 28160 return display_object3d(title,points,CImgList<uintT>(),centering,
philpem@5 28161 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28162 display_axes,pose_matrix);
philpem@5 28163 }
philpem@5 28164
philpem@5 28165 T _display_object3d_at2(const int i, const int j) const {
philpem@5 28166 return atXY(i,j,0,0,0);
philpem@5 28167 }
philpem@5 28168
philpem@5 28169 template<typename tp, typename tf, typename tc, typename to>
philpem@5 28170 const CImg<T>& _display_object3d(CImgDisplay& disp, const char *const title,
philpem@5 28171 const tp& points, const unsigned int Npoints,
philpem@5 28172 const CImgList<tf>& primitives,
philpem@5 28173 const CImgList<tc>& colors, const to& opacities,
philpem@5 28174 const bool centering,
philpem@5 28175 const int render_static, const int render_motion,
philpem@5 28176 const bool double_sided, const float focale,
philpem@5 28177 const float specular_light, const float specular_shine,
philpem@5 28178 const bool display_axes, float *const pose_matrix) const {
philpem@5 28179
philpem@5 28180 // Check input arguments
philpem@5 28181 if (!points || !Npoints)
philpem@5 28182 throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.",
philpem@5 28183 pixel_type());
philpem@5 28184 if (is_empty()) {
philpem@5 28185 if (disp) return CImg<T>(disp.width,disp.height,1,colors[0].size(),0).
philpem@5 28186 _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
philpem@5 28187 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28188 display_axes,pose_matrix);
philpem@5 28189 else return CImg<T>(cimg_fitscreen(640,480,1),1,colors[0].size(),0).
philpem@5 28190 _display_object3d(disp,title,points,Npoints,primitives,colors,opacities,centering,
philpem@5 28191 render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28192 display_axes,pose_matrix);
philpem@5 28193 }
philpem@5 28194 if (!primitives) {
philpem@5 28195 CImgList<tf> nprimitives(Npoints,1,1,1,1);
philpem@5 28196 cimglist_for(nprimitives,l) nprimitives(l,0) = l;
philpem@5 28197 return _display_object3d(disp,title,points,Npoints,nprimitives,colors,opacities,
philpem@5 28198 centering,render_static,render_motion,double_sided,focale,specular_light,specular_shine,
philpem@5 28199 display_axes,pose_matrix);
philpem@5 28200 }
philpem@5 28201 if (!disp) {
philpem@5 28202 char ntitle[64] = { 0 }; if (!title) { cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); }
philpem@5 28203 disp.assign(cimg_fitscreen(width,height,depth),title?title:ntitle,1);
philpem@5 28204 }
philpem@5 28205
philpem@5 28206 CImgList<tc> _colors;
philpem@5 28207 if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
philpem@5 28208 const CImgList<tc> &ncolors = colors?colors:_colors;
philpem@5 28209
philpem@5 28210 // Init 3D objects and compute object statistics
philpem@5 28211 CImg<floatT>
philpem@5 28212 pose, rot_mat, zbuffer,
philpem@5 28213 centered_points = centering?CImg<floatT>(Npoints,3):CImg<floatT>(),
philpem@5 28214 rotated_points(Npoints,3),
philpem@5 28215 bbox_points, rotated_bbox_points,
philpem@5 28216 axes_points, rotated_axes_points,
philpem@5 28217 bbox_opacities, axes_opacities;
philpem@5 28218 CImgList<uintT> bbox_primitives, axes_primitives;
philpem@5 28219 CImgList<T> bbox_colors, bbox_colors2, axes_colors;
philpem@5 28220 float dx = 0, dy = 0, dz = 0, ratio = 1;
philpem@5 28221
philpem@5 28222 T minval = (T)0, maxval = (T)255;
philpem@5 28223 if (disp.normalization && colors) {
philpem@5 28224 minval = colors.minmax(maxval);
philpem@5 28225 if (minval==maxval) { minval = (T)0; maxval = (T)255; }
philpem@5 28226 }
philpem@5 28227 const float meanval = (float)mean();
philpem@5 28228 bool color_model = true;
philpem@5 28229 if (cimg::abs(meanval-minval)>cimg::abs(meanval-maxval)) color_model = false;
philpem@5 28230 const CImg<T>
philpem@5 28231 background_color(1,1,1,dim,color_model?minval:maxval),
philpem@5 28232 foreground_color(1,1,1,dim,color_model?maxval:minval);
philpem@5 28233
philpem@5 28234 float xm = cimg::type<float>::max(), xM = 0, ym = xm, yM = 0, zm = xm, zM = 0;
philpem@5 28235 for (unsigned int i = 0; i<Npoints; ++i) {
philpem@5 28236 const float
philpem@5 28237 x = points._display_object3d_at2(i,0),
philpem@5 28238 y = points._display_object3d_at2(i,1),
philpem@5 28239 z = points._display_object3d_at2(i,2);
philpem@5 28240 if (x<xm) xm = x;
philpem@5 28241 if (x>xM) xM = x;
philpem@5 28242 if (y<ym) ym = y;
philpem@5 28243 if (y>yM) yM = y;
philpem@5 28244 if (z<zm) zm = z;
philpem@5 28245 if (z>zM) zM = z;
philpem@5 28246 }
philpem@5 28247 const float delta = cimg::max(xM-xm,yM-ym,zM-zm);
philpem@5 28248
philpem@5 28249 if (display_axes) {
philpem@5 28250 rotated_axes_points = axes_points.assign(7,3,1,1,
philpem@5 28251 0,20,0,0,22,-6,-6,
philpem@5 28252 0,0,20,0,-6,22,-6,
philpem@5 28253 0,0,0,20,0,0,22);
philpem@5 28254 axes_opacities.assign(3,1,1,1,1);
philpem@5 28255 axes_colors.assign(3,dim,1,1,1,foreground_color[0]);
philpem@5 28256 axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3);
philpem@5 28257 }
philpem@5 28258
philpem@5 28259 // Begin user interaction loop
philpem@5 28260 CImg<T> visu0(*this), visu;
philpem@5 28261 bool init = true, clicked = false, redraw = true;
philpem@5 28262 unsigned int key = 0;
philpem@5 28263 int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
philpem@5 28264 disp.show().flush();
philpem@5 28265
philpem@5 28266 while (!disp.is_closed && !key) {
philpem@5 28267
philpem@5 28268 // Init object position and scale if necessary
philpem@5 28269 if (init) {
philpem@5 28270 ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0;
philpem@5 28271 dx = 0.5f*(xM + xm); dy = 0.5f*(yM + ym); dz = 0.5f*(zM + zm);
philpem@5 28272 if (centering) {
philpem@5 28273 cimg_forX(centered_points,l) {
philpem@5 28274 centered_points(l,0) = (float)((points(l,0) - dx)*ratio);
philpem@5 28275 centered_points(l,1) = (float)((points(l,1) - dy)*ratio);
philpem@5 28276 centered_points(l,2) = (float)((points(l,2) - dz)*ratio);
philpem@5 28277 }
philpem@5 28278 }
philpem@5 28279
philpem@5 28280 if (render_static<0 || render_motion<0) {
philpem@5 28281 rotated_bbox_points = bbox_points.assign(8,3,1,1,
philpem@5 28282 xm,xM,xM,xm,xm,xM,xM,xm,
philpem@5 28283 ym,ym,yM,yM,ym,ym,yM,yM,
philpem@5 28284 zm,zm,zm,zm,zM,zM,zM,zM);
philpem@5 28285 bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6);
philpem@5 28286 bbox_colors.assign(6,dim,1,1,1,background_color[0]);
philpem@5 28287 bbox_colors2.assign(6,dim,1,1,1,foreground_color[0]);
philpem@5 28288 bbox_opacities.assign(bbox_colors.size,1,1,1,0.3f);
philpem@5 28289 }
philpem@5 28290
philpem@5 28291 if (!pose) {
philpem@5 28292 if (pose_matrix) pose = CImg<floatT>(pose_matrix,4,4,1,1,false);
philpem@5 28293 else pose = CImg<floatT>::identity_matrix(4);
philpem@5 28294 }
philpem@5 28295 init = false;
philpem@5 28296 redraw = true;
philpem@5 28297 }
philpem@5 28298
philpem@5 28299 // Rotate and Draw 3D object
philpem@5 28300 if (redraw) {
philpem@5 28301 const float
philpem@5 28302 r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0),
philpem@5 28303 r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1),
philpem@5 28304 r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2);
philpem@5 28305 if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) {
philpem@5 28306 if (centering) cimg_forX(centered_points,l) {
philpem@5 28307 const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2);
philpem@5 28308 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
philpem@5 28309 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
philpem@5 28310 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
philpem@5 28311 } else for (unsigned int l = 0; l<Npoints; ++l) {
philpem@5 28312 const float
philpem@5 28313 x = (float)points._display_object3d_at2(l,0),
philpem@5 28314 y = (float)points._display_object3d_at2(l,1),
philpem@5 28315 z = (float)points._display_object3d_at2(l,2);
philpem@5 28316 rotated_points(l,0) = r00*x + r10*y + r20*z + r30;
philpem@5 28317 rotated_points(l,1) = r01*x + r11*y + r21*z + r31;
philpem@5 28318 rotated_points(l,2) = r02*x + r12*y + r22*z + r32;
philpem@5 28319 }
philpem@5 28320 } else {
philpem@5 28321 if (!centering) cimg_forX(bbox_points,l) {
philpem@5 28322 const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2);
philpem@5 28323 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
philpem@5 28324 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
philpem@5 28325 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
philpem@5 28326 } else cimg_forX(bbox_points,l) {
philpem@5 28327 const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio;
philpem@5 28328 rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30;
philpem@5 28329 rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31;
philpem@5 28330 rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32;
philpem@5 28331 }
philpem@5 28332 }
philpem@5 28333
philpem@5 28334 // Draw object
philpem@5 28335 visu = visu0;
philpem@5 28336 if ((clicked && render_motion<0) || (!clicked && render_static<0))
philpem@5 28337 visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale).
philpem@5 28338 draw_object3d(visu.width/2.0f,visu.height/2.0f,0,rotated_bbox_points,bbox_primitives,bbox_colors2,1,false,focale);
philpem@5 28339 else visu.draw_object3d(visu.width/2.0f,visu.height/2.0f,0,
philpem@5 28340 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
philpem@5 28341 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
philpem@5 28342 (!clicked && render_static>0)?zbuffer.fill(0).ptr():0);
philpem@5 28343
philpem@5 28344 // Draw axes
philpem@5 28345 if (display_axes) {
philpem@5 28346 const float Xaxes = 25, Yaxes = visu.height - 35.0f;
philpem@5 28347 cimg_forX(axes_points,l) {
philpem@5 28348 const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2);
philpem@5 28349 rotated_axes_points(l,0) = r00*x + r10*y + r20*z;
philpem@5 28350 rotated_axes_points(l,1) = r01*x + r11*y + r21*z;
philpem@5 28351 rotated_axes_points(l,2) = r02*x + r12*y + r22*z;
philpem@5 28352 }
philpem@5 28353 axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f;
philpem@5 28354 axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f;
philpem@5 28355 axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f;
philpem@5 28356 visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale).
philpem@5 28357 draw_text((int)(Xaxes+rotated_axes_points(4,0)),
philpem@5 28358 (int)(Yaxes+rotated_axes_points(4,1)),
philpem@5 28359 "X",axes_colors[0].data,0,axes_opacities(0,0),11).
philpem@5 28360 draw_text((int)(Xaxes+rotated_axes_points(5,0)),
philpem@5 28361 (int)(Yaxes+rotated_axes_points(5,1)),
philpem@5 28362 "Y",axes_colors[1].data,0,axes_opacities(1,0),11).
philpem@5 28363 draw_text((int)(Xaxes+rotated_axes_points(6,0)),
philpem@5 28364 (int)(Yaxes+rotated_axes_points(6,1)),
philpem@5 28365 "Z",axes_colors[2].data,0,axes_opacities(2,0),11);
philpem@5 28366 }
philpem@5 28367 visu.display(disp);
philpem@5 28368 if (!clicked || render_motion==render_static) redraw = false;
philpem@5 28369 }
philpem@5 28370
philpem@5 28371 // Handle user interaction
philpem@5 28372 disp.wait();
philpem@5 28373 if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) {
philpem@5 28374 redraw = true;
philpem@5 28375 if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; }
philpem@5 28376 else { x1 = disp.mouse_x; y1 = disp.mouse_y; }
philpem@5 28377 if (disp.button&1) {
philpem@5 28378 const float
philpem@5 28379 R = 0.45f*cimg::min(disp.width,disp.height),
philpem@5 28380 R2 = R*R,
philpem@5 28381 u0 = (float)(x0-disp.dimx()/2),
philpem@5 28382 v0 = (float)(y0-disp.dimy()/2),
philpem@5 28383 u1 = (float)(x1-disp.dimx()/2),
philpem@5 28384 v1 = (float)(y1-disp.dimy()/2),
philpem@5 28385 n0 = (float)cimg_std::sqrt(u0*u0+v0*v0),
philpem@5 28386 n1 = (float)cimg_std::sqrt(u1*u1+v1*v1),
philpem@5 28387 nu0 = n0>R?(u0*R/n0):u0,
philpem@5 28388 nv0 = n0>R?(v0*R/n0):v0,
philpem@5 28389 nw0 = (float)cimg_std::sqrt(cimg::max(0,R2-nu0*nu0-nv0*nv0)),
philpem@5 28390 nu1 = n1>R?(u1*R/n1):u1,
philpem@5 28391 nv1 = n1>R?(v1*R/n1):v1,
philpem@5 28392 nw1 = (float)cimg_std::sqrt(cimg::max(0,R2-nu1*nu1-nv1*nv1)),
philpem@5 28393 u = nv0*nw1-nw0*nv1,
philpem@5 28394 v = nw0*nu1-nu0*nw1,
philpem@5 28395 w = nv0*nu1-nu0*nv1,
philpem@5 28396 n = (float)cimg_std::sqrt(u*u+v*v+w*w),
philpem@5 28397 alpha = (float)cimg_std::asin(n/R2);
philpem@5 28398 rot_mat = CImg<floatT>::rotation_matrix(u,v,w,alpha);
philpem@5 28399 rot_mat *= pose.get_crop(0,0,2,2);
philpem@5 28400 pose.draw_image(rot_mat);
philpem@5 28401 x0=x1; y0=y1;
philpem@5 28402 }
philpem@5 28403 if (disp.button&2) { pose(3,2)+=(y1-y0); x0 = x1; y0 = y1; }
philpem@5 28404 if (disp.wheel) { pose(3,2)-=focale*disp.wheel/10; disp.wheel = 0; }
philpem@5 28405 if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0 = x1; y0 = y1; }
philpem@5 28406 if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg<floatT>::identity_matrix(4); }
philpem@5 28407 } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; }
philpem@5 28408
philpem@5 28409 switch (key = disp.key) {
philpem@5 28410 case 0 : case cimg::keyCTRLLEFT : disp.key = key = 0; break;
philpem@5 28411 case cimg::keyD: if (disp.is_keyCTRLLEFT) {
philpem@5 28412 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
philpem@5 28413 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
philpem@5 28414 disp.key = key = 0;
philpem@5 28415 } break;
philpem@5 28416 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
philpem@5 28417 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
philpem@5 28418 disp.key = key = 0;
philpem@5 28419 } break;
philpem@5 28420 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
philpem@5 28421 disp.normalscreen().resize(cimg_fitscreen(width,height,depth),false).is_resized = true;
philpem@5 28422 disp.key = key = 0;
philpem@5 28423 } break;
philpem@5 28424 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
philpem@5 28425 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
philpem@5 28426 disp.key = key = 0;
philpem@5 28427 } break;
philpem@5 28428 case cimg::keyZ : if (disp.is_keyCTRLLEFT) { // Enable/Disable Z-buffer
philpem@5 28429 if (zbuffer) zbuffer.assign();
philpem@5 28430 else zbuffer.assign(disp.width,disp.height);
philpem@5 28431 disp.key = key = 0; redraw = true;
philpem@5 28432 } break;
philpem@5 28433 case cimg::keyS : if (disp.is_keyCTRLLEFT) { // Save snapshot
philpem@5 28434 static unsigned int snap_number = 0;
philpem@5 28435 char filename[32] = { 0 };
philpem@5 28436 cimg_std::FILE *file;
philpem@5 28437 do {
philpem@5 28438 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
philpem@5 28439 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 28440 } while (file);
philpem@5 28441 (+visu).draw_text(2,2,"Saving BMP snapshot...",foreground_color,background_color,1,11).display(disp);
philpem@5 28442 visu.save(filename);
philpem@5 28443 visu.draw_text(2,2,"Snapshot '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
philpem@5 28444 disp.key = key = 0;
philpem@5 28445 } break;
philpem@5 28446 case cimg::keyO : if (disp.is_keyCTRLLEFT) { // Save object as an .OFF file
philpem@5 28447 static unsigned int snap_number = 0;
philpem@5 28448 char filename[32] = { 0 };
philpem@5 28449 cimg_std::FILE *file;
philpem@5 28450 do {
philpem@5 28451 cimg_std::sprintf(filename,"CImg_%.4u.off",snap_number++);
philpem@5 28452 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 28453 } while (file);
philpem@5 28454 visu.draw_text(2,2,"Saving object...",foreground_color,background_color,1,11).display(disp);
philpem@5 28455 points.save_off(filename,primitives,ncolors);
philpem@5 28456 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
philpem@5 28457 disp.key = key = 0;
philpem@5 28458 } break;
philpem@5 28459 #ifdef cimg_use_board
philpem@5 28460 case cimg::keyP : if (disp.is_keyCTRLLEFT) { // Save object as a .EPS file
philpem@5 28461 static unsigned int snap_number = 0;
philpem@5 28462 char filename[32] = { 0 };
philpem@5 28463 cimg_std::FILE *file;
philpem@5 28464 do {
philpem@5 28465 cimg_std::sprintf(filename,"CImg_%.4u.eps",snap_number++);
philpem@5 28466 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 28467 } while (file);
philpem@5 28468 visu.draw_text(2,2,"Saving EPS snapshot...",foreground_color,background_color,1,11).display(disp);
philpem@5 28469 BoardLib::Board board;
philpem@5 28470 (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
philpem@5 28471 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
philpem@5 28472 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
philpem@5 28473 zbuffer.fill(0).ptr());
philpem@5 28474 board.saveEPS(filename);
philpem@5 28475 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
philpem@5 28476 disp.key = key = 0;
philpem@5 28477 } break;
philpem@5 28478 case cimg::keyV : if (disp.is_keyCTRLLEFT) { // Save object as a .SVG file
philpem@5 28479 static unsigned int snap_number = 0;
philpem@5 28480 char filename[32] = { 0 };
philpem@5 28481 cimg_std::FILE *file;
philpem@5 28482 do {
philpem@5 28483 cimg_std::sprintf(filename,"CImg_%.4u.svg",snap_number++);
philpem@5 28484 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 28485 } while (file);
philpem@5 28486 visu.draw_text(2,2,"Saving SVG snapshot...",foreground_color,background_color,1,11).display(disp);
philpem@5 28487 BoardLib::Board board;
philpem@5 28488 (+visu).draw_object3d(board,visu.width/2.0f, visu.height/2.0f, 0,
philpem@5 28489 rotated_points,primitives,ncolors,opacities,clicked?render_motion:render_static,
philpem@5 28490 double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000,specular_light,specular_shine,
philpem@5 28491 zbuffer.fill(0).ptr());
philpem@5 28492 board.saveSVG(filename);
philpem@5 28493 visu.draw_text(2,2,"Object '%s' saved.",foreground_color,background_color,1,11,filename).display(disp);
philpem@5 28494 disp.key = key = 0;
philpem@5 28495 } break;
philpem@5 28496 #endif
philpem@5 28497 }
philpem@5 28498 if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); if (zbuffer) zbuffer.assign(disp.width,disp.height); redraw = true; }
philpem@5 28499 }
philpem@5 28500 if (pose_matrix) cimg_std::memcpy(pose_matrix,pose.data,16*sizeof(float));
philpem@5 28501 disp.button = 0;
philpem@5 28502 disp.key = key;
philpem@5 28503 return *this;
philpem@5 28504 }
philpem@5 28505
philpem@5 28506 //! High-level interface for displaying a graph.
philpem@5 28507 const CImg<T>& display_graph(CImgDisplay &disp,
philpem@5 28508 const unsigned int plot_type=1, const unsigned int vertex_type=1,
philpem@5 28509 const char *const labelx=0, const double xmin=0, const double xmax=0,
philpem@5 28510 const char *const labely=0, const double ymin=0, const double ymax=0) const {
philpem@5 28511 if (is_empty())
philpem@5 28512 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 28513 pixel_type(),width,height,depth,dim,data);
philpem@5 28514 const unsigned int siz = width*height*depth, onormalization = disp.normalization;
philpem@5 28515 if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
philpem@5 28516 disp.show().flush().normalization = 0;
philpem@5 28517 double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax;
philpem@5 28518 if (nxmin==nxmax) { nxmin = 0; nxmax = siz - 1.0; }
philpem@5 28519 int x0 = 0, x1 = size()/dimv()-1, key = 0;
philpem@5 28520
philpem@5 28521 for (bool reset_view = true, resize_disp = false; !key && !disp.is_closed; ) {
philpem@5 28522 if (reset_view) { x0 = 0; x1 = size()/dimv()-1; y0 = ymin; y1 = ymax; reset_view = false; }
philpem@5 28523 CImg<T> zoom(x1-x0+1,1,1,dimv());
philpem@5 28524 cimg_forV(*this,k) zoom.get_shared_channel(k) = CImg<T>(ptr(x0,0,0,k),x1-x0+1,1,1,1,true);
philpem@5 28525
philpem@5 28526 if (y0==y1) y0 = zoom.minmax(y1);
philpem@5 28527 if (y0==y1) { --y0; ++y1; }
philpem@5 28528 const CImg<intT> selection = zoom.get_select_graph(disp,plot_type,vertex_type,
philpem@5 28529 labelx,nxmin + x0*(nxmax-nxmin)/siz,nxmin + x1*(nxmax-nxmin)/siz,
philpem@5 28530 labely,y0,y1);
philpem@5 28531
philpem@5 28532 const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
philpem@5 28533 if (selection[0]>=0 && selection[2]>=0) {
philpem@5 28534 x1 = x0 + selection[2];
philpem@5 28535 x0 += selection[0];
philpem@5 28536 if (x0==x1) reset_view = true;
philpem@5 28537 if (selection[1]>=0 && selection[3]>=0) {
philpem@5 28538 y0 = y1 - selection[3]*(y1-y0)/(disp.dimy()-32);
philpem@5 28539 y1 -= selection[1]*(y1-y0)/(disp.dimy()-32);
philpem@5 28540 }
philpem@5 28541 } else {
philpem@5 28542 bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false;
philpem@5 28543 switch (key = disp.key) {
philpem@5 28544 case cimg::keyHOME : case cimg::keyBACKSPACE : reset_view = resize_disp = true; key = 0; break;
philpem@5 28545 case cimg::keyPADADD : go_in = true; key = 0; break;
philpem@5 28546 case cimg::keyPADSUB : go_out = true; key = 0; break;
philpem@5 28547 case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; key = 0; break;
philpem@5 28548 case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; key = 0; break;
philpem@5 28549 case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; key = 0; break;
philpem@5 28550 case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; key = 0; break;
philpem@5 28551 case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; break;
philpem@5 28552 case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; break;
philpem@5 28553 case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; break;
philpem@5 28554 case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; break;
philpem@5 28555 }
philpem@5 28556 if (disp.wheel) go_out = !(go_in = disp.wheel>0);
philpem@5 28557
philpem@5 28558 if (go_in) {
philpem@5 28559 const int
philpem@5 28560 xsiz = x1 - x0,
philpem@5 28561 mx = (mouse_x-16)*xsiz/(disp.dimx()-32),
philpem@5 28562 cx = x0 + (mx<0?0:(mx>=xsiz?xsiz:mx));
philpem@5 28563 if (x1-x0>4) {
philpem@5 28564 x0 = cx - 7*(cx-x0)/8; x1 = cx + 7*(x1-cx)/8;
philpem@5 28565 if (disp.is_keyCTRLLEFT) {
philpem@5 28566 const double
philpem@5 28567 ysiz = y1 - y0,
philpem@5 28568 my = (mouse_y-16)*ysiz/(disp.dimy()-32),
philpem@5 28569 cy = y1 - (my<0?0:(my>=ysiz?ysiz:my));
philpem@5 28570 y0 = cy - 7*(cy-y0)/8; y1 = cy + 7*(y1-cy)/8;
philpem@5 28571 } else y0 = y1 = 0;
philpem@5 28572 }
philpem@5 28573 }
philpem@5 28574 if (go_out) {
philpem@5 28575 const int deltax = (x1-x0)/8, ndeltax = deltax?deltax:(siz>1?1:0);
philpem@5 28576 x0-=ndeltax; x1+=ndeltax;
philpem@5 28577 if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz-1; }
philpem@5 28578 if (x1>=(int)siz) { x0-=(x1-siz+1); x1 = (int)siz-1; if (x0<0) x0 = 0; }
philpem@5 28579 if (disp.is_keyCTRLLEFT) {
philpem@5 28580 const double deltay = (y1-y0)/8, ndeltay = deltay?deltay:0.01;
philpem@5 28581 y0-=ndeltay; y1+=ndeltay;
philpem@5 28582 }
philpem@5 28583 }
philpem@5 28584 if (go_left) {
philpem@5 28585 const int delta = (x1-x0)/5, ndelta = delta?delta:1;
philpem@5 28586 if (x0-ndelta>=0) { x0-=ndelta; x1-=ndelta; }
philpem@5 28587 else { x1-=x0; x0 = 0; }
philpem@5 28588 go_left = false;
philpem@5 28589 }
philpem@5 28590 if (go_right) {
philpem@5 28591 const int delta = (x1-x0)/5, ndelta = delta?delta:1;
philpem@5 28592 if (x1+ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; }
philpem@5 28593 else { x0+=(siz-1-x1); x1 = siz-1; }
philpem@5 28594 go_right = false;
philpem@5 28595 }
philpem@5 28596 if (go_up) {
philpem@5 28597 const double delta = (y1-y0)/10, ndelta = delta?delta:1;
philpem@5 28598 y0+=ndelta; y1+=ndelta;
philpem@5 28599 go_up = false;
philpem@5 28600 }
philpem@5 28601 if (go_down) {
philpem@5 28602 const double delta = (y1-y0)/10, ndelta = delta?delta:1;
philpem@5 28603 y0-=ndelta; y1-=ndelta;
philpem@5 28604 go_down = false;
philpem@5 28605 }
philpem@5 28606 }
philpem@5 28607 }
philpem@5 28608 disp.normalization = onormalization;
philpem@5 28609 return *this;
philpem@5 28610 }
philpem@5 28611
philpem@5 28612 //! High-level interface for displaying a graph.
philpem@5 28613 const CImg<T>& display_graph(const char *const title=0,
philpem@5 28614 const unsigned int plot_type=1, const unsigned int vertex_type=1,
philpem@5 28615 const char *const labelx=0, const double xmin=0, const double xmax=0,
philpem@5 28616 const char *const labely=0, const double ymin=0, const double ymax=0) const {
philpem@5 28617 if (is_empty())
philpem@5 28618 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 28619 pixel_type(),width,height,depth,dim,data);
philpem@5 28620 char ntitle[64] = { 0 }; if (!title) cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type());
philpem@5 28621 CImgDisplay disp(cimg_fitscreen(640,480,1),title?title:ntitle,0);
philpem@5 28622 return display_graph(disp,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax);
philpem@5 28623 }
philpem@5 28624
philpem@5 28625 //! Select sub-graph in a graph.
philpem@5 28626 CImg<intT> get_select_graph(CImgDisplay &disp,
philpem@5 28627 const unsigned int plot_type=1, const unsigned int vertex_type=1,
philpem@5 28628 const char *const labelx=0, const double xmin=0, const double xmax=0,
philpem@5 28629 const char *const labely=0, const double ymin=0, const double ymax=0) const {
philpem@5 28630 if (is_empty())
philpem@5 28631 throw CImgInstanceException("CImg<%s>::display_graph() : Instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 28632 pixel_type(),width,height,depth,dim,data);
philpem@5 28633 const unsigned int siz = width*height*depth, onormalization = disp.normalization;
philpem@5 28634 if (!disp) { char ntitle[64] = { 0 }; cimg_std::sprintf(ntitle,"CImg<%s>",pixel_type()); disp.assign(640,480,ntitle,0); }
philpem@5 28635 disp.show().key = disp.normalization = disp.button = disp.wheel = 0; // Must keep 'key' field unchanged.
philpem@5 28636 double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax;
philpem@5 28637 if (nymin==nymax) nymin = (Tfloat)minmax(nymax);
philpem@5 28638 if (nymin==nymax) { --nymin; ++nymax; }
philpem@5 28639 if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.0; }
philpem@5 28640
philpem@5 28641 const unsigned char black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 220,220,220 };
philpem@5 28642 const unsigned char gray2[] = { 110,110,110 }, ngray[] = { 35,35,35 };
philpem@5 28643 static unsigned int odimv = 0;
philpem@5 28644 static CImg<ucharT> palette;
philpem@5 28645 if (odimv!=dim) {
philpem@5 28646 odimv = dim;
philpem@5 28647 palette = CImg<ucharT>(3,dim,1,1,120).noise(70,1);
philpem@5 28648 if (dim==1) { palette[0] = palette[1] = 120; palette[2] = 200; }
philpem@5 28649 else {
philpem@5 28650 palette(0,0) = 220; palette(1,0) = 10; palette(2,0) = 10;
philpem@5 28651 if (dim>1) { palette(0,1) = 10; palette(1,1) = 220; palette(2,1) = 10; }
philpem@5 28652 if (dim>2) { palette(0,2) = 10; palette(1,2) = 10; palette(2,2) = 220; }
philpem@5 28653 }
philpem@5 28654 }
philpem@5 28655
philpem@5 28656 CImg<ucharT> visu0, visu, graph, text, axes;
philpem@5 28657 const unsigned int whz = width*height*depth;
philpem@5 28658 int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2;
philpem@5 28659 char message[1024] = { 0 };
philpem@5 28660 unsigned int okey = 0, obutton = 0;
philpem@5 28661 CImg_3x3(I,unsigned char);
philpem@5 28662
philpem@5 28663 for (bool selected = false; !selected && !disp.is_closed && !okey && !disp.wheel; ) {
philpem@5 28664 const int mouse_x = disp.mouse_x, mouse_y = disp.mouse_y;
philpem@5 28665 const unsigned int key = disp.key, button = disp.button;
philpem@5 28666
philpem@5 28667 // Generate graph representation.
philpem@5 28668 if (!visu0) {
philpem@5 28669 visu0.assign(disp.dimx(),disp.dimy(),1,3,220);
philpem@5 28670 const int gdimx = disp.dimx() - 32, gdimy = disp.dimy() - 32;
philpem@5 28671 if (gdimx>0 && gdimy>0) {
philpem@5 28672 graph.assign(gdimx,gdimy,1,3,255);
philpem@5 28673 graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333);
philpem@5 28674 cimg_forV(*this,k) graph.draw_graph(get_shared_channel(k),&palette(0,k),(plot_type!=3 || dim==1)?1:0.6f,
philpem@5 28675 plot_type,vertex_type,nymax,nymin);
philpem@5 28676
philpem@5 28677 axes.assign(gdimx,gdimy,1,1,0);
philpem@5 28678 const float
philpem@5 28679 dx = (float)cimg::abs(nxmax-nxmin), dy = (float)cimg::abs(nymax-nymin),
philpem@5 28680 px = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dx)-2.0),
philpem@5 28681 py = (float)cimg_std::pow(10.0,(int)cimg_std::log10(dy)-2.0);
philpem@5 28682 const CImg<Tdouble>
philpem@5 28683 seqx = CImg<Tdouble>::sequence(1 + gdimx/60,nxmin,nxmax).round(px),
philpem@5 28684 seqy = CImg<Tdouble>::sequence(1 + gdimy/60,nymax,nymin).round(py);
philpem@5 28685 axes.draw_axis(seqx,seqy,white);
philpem@5 28686 if (nymin>0) axes.draw_axis(seqx,gdimy-1,gray);
philpem@5 28687 if (nymax<0) axes.draw_axis(seqx,0,gray);
philpem@5 28688 if (nxmin>0) axes.draw_axis(0,seqy,gray);
philpem@5 28689 if (nxmax<0) axes.draw_axis(gdimx-1,seqy,gray);
philpem@5 28690
philpem@5 28691 cimg_for3x3(axes,x,y,0,0,I)
philpem@5 28692 if (Icc) {
philpem@5 28693 if (Icc==255) cimg_forV(graph,k) graph(x,y,k) = 0;
philpem@5 28694 else cimg_forV(graph,k) graph(x,y,k) = (unsigned char)(2*graph(x,y,k)/3);
philpem@5 28695 }
philpem@5 28696 else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) cimg_forV(graph,k) graph(x,y,k) = (graph(x,y,k)+255)/2;
philpem@5 28697
philpem@5 28698 visu0.draw_image(16,16,graph);
philpem@5 28699 visu0.draw_line(15,15,16+gdimx,15,gray2).draw_line(16+gdimx,15,16+gdimx,16+gdimy,gray2).
philpem@5 28700 draw_line(16+gdimx,16+gdimy,15,16+gdimy,white).draw_line(15,16+gdimy,15,15,white);
philpem@5 28701 } else graph.assign();
philpem@5 28702 text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1);
philpem@5 28703 visu0.draw_image((visu0.dimx()-text.dimx())/2,visu0.dimy()-14,~text);
philpem@5 28704 text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1).rotate(-90);
philpem@5 28705 visu0.draw_image(2,(visu0.dimy()-text.dimy())/2,~text);
philpem@5 28706 visu.assign();
philpem@5 28707 }
philpem@5 28708
philpem@5 28709 // Generate and display current view.
philpem@5 28710 if (!visu) {
philpem@5 28711 visu.assign(visu0);
philpem@5 28712 if (graph && x0>=0 && x1>=0) {
philpem@5 28713 const int
philpem@5 28714 nx0 = x0<=x1?x0:x1,
philpem@5 28715 nx1 = x0<=x1?x1:x0,
philpem@5 28716 ny0 = y0<=y1?y0:y1,
philpem@5 28717 ny1 = y0<=y1?y1:y0,
philpem@5 28718 sx0 = 16 + nx0*(visu.dimx()-32)/whz,
philpem@5 28719 sx1 = 15 + (nx1+1)*(visu.dimx()-32)/whz,
philpem@5 28720 sy0 = 16 + ny0,
philpem@5 28721 sy1 = 16 + ny1;
philpem@5 28722
philpem@5 28723 if (y0>=0 && y1>=0)
philpem@5 28724 visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU);
philpem@5 28725 else visu.draw_rectangle(sx0,0,sx1,visu.dimy()-17,gray,0.5f).
philpem@5 28726 draw_line(sx0,16,sx0,visu.dimy()-17,black,0.5f,0xCCCCCCCCU).
philpem@5 28727 draw_line(sx1,16,sx1,visu.dimy()-17,black,0.5f,0xCCCCCCCCU);
philpem@5 28728 }
philpem@5 28729 if (mouse_x>=16 && mouse_y>=16 && mouse_x<visu.dimx()-16 && mouse_y<visu.dimy()-16) {
philpem@5 28730 if (graph) visu.draw_line(mouse_x,16,mouse_x,visu.dimy()-17,black,0.5f,0x55555555U);
philpem@5 28731 const unsigned x = (mouse_x-16)*whz/(disp.dimx()-32);
philpem@5 28732 const double cx = nxmin + x*(nxmax-nxmin)/whz;
philpem@5 28733 if (dim>=7)
philpem@5 28734 cimg_std::sprintf(message,"Value[%g] = ( %g %g %g ... %g %g %g )",cx,
philpem@5 28735 (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2),
philpem@5 28736 (double)(*this)(x,0,0,dim-4),(double)(*this)(x,0,0,dim-3),(double)(*this)(x,0,0,dim-1));
philpem@5 28737 else {
philpem@5 28738 cimg_std::sprintf(message,"Value[%g] = ( ",cx);
philpem@5 28739 cimg_forV(*this,k) cimg_std::sprintf(message+cimg::strlen(message),"%g ",(double)(*this)(x,0,0,k));
philpem@5 28740 cimg_std::sprintf(message+cimg::strlen(message),")");
philpem@5 28741 }
philpem@5 28742 if (x0>=0 && x1>=0) {
philpem@5 28743 const int
philpem@5 28744 nx0 = x0<=x1?x0:x1,
philpem@5 28745 nx1 = x0<=x1?x1:x0,
philpem@5 28746 ny0 = y0<=y1?y0:y1,
philpem@5 28747 ny1 = y0<=y1?y1:y0;
philpem@5 28748 const double
philpem@5 28749 cx0 = nxmin + nx0*(nxmax-nxmin)/(visu.dimx()-32),
philpem@5 28750 cx1 = nxmin + nx1*(nxmax-nxmin)/(visu.dimx()-32),
philpem@5 28751 cy0 = nymax - ny0*(nymax-nymin)/(visu.dimy()-32),
philpem@5 28752 cy1 = nymax - ny1*(nymax-nymin)/(visu.dimy()-32);
philpem@5 28753 if (y0>=0 && y1>=0)
philpem@5 28754 cimg_std::sprintf(message+cimg::strlen(message)," - Range ( %g, %g ) - ( %g, %g )",cx0,cy0,cx1,cy1);
philpem@5 28755 else
philpem@5 28756 cimg_std::sprintf(message+cimg::strlen(message)," - Range [ %g - %g ]",cx0,cx1);
philpem@5 28757 }
philpem@5 28758 text.assign().draw_text(0,0,message,white,ngray,1);
philpem@5 28759 visu.draw_image((visu.dimx()-text.dimx())/2,2,~text);
philpem@5 28760 }
philpem@5 28761 visu.display(disp);
philpem@5 28762 }
philpem@5 28763
philpem@5 28764 // Test keys.
philpem@5 28765 switch (okey = key) {
philpem@5 28766 case cimg::keyCTRLLEFT : okey = 0; break;
philpem@5 28767 case cimg::keyD : if (disp.is_keyCTRLLEFT) {
philpem@5 28768 disp.normalscreen().resize(CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,false),
philpem@5 28769 CImgDisplay::_fitscreen(3*disp.width/2,3*disp.height/2,1,128,-100,true),false).is_resized = true;
philpem@5 28770 disp.key = okey = 0;
philpem@5 28771 } break;
philpem@5 28772 case cimg::keyC : if (disp.is_keyCTRLLEFT) {
philpem@5 28773 disp.normalscreen().resize(cimg_fitscreen(2*disp.width/3,2*disp.height/3,1),false).is_resized = true;
philpem@5 28774 disp.key = okey = 0;
philpem@5 28775 } break;
philpem@5 28776 case cimg::keyR : if (disp.is_keyCTRLLEFT) {
philpem@5 28777 disp.normalscreen().resize(cimg_fitscreen(640,480,1),false).is_resized = true;
philpem@5 28778 disp.key = okey = 0;
philpem@5 28779 } break;
philpem@5 28780 case cimg::keyF : if (disp.is_keyCTRLLEFT) {
philpem@5 28781 disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true;
philpem@5 28782 disp.key = okey = 0;
philpem@5 28783 } break;
philpem@5 28784 case cimg::keyS : if (disp.is_keyCTRLLEFT) {
philpem@5 28785 static unsigned int snap_number = 0;
philpem@5 28786 if (visu || visu0) {
philpem@5 28787 CImg<ucharT> &screen = visu?visu:visu0;
philpem@5 28788 char filename[32] = { 0 };
philpem@5 28789 cimg_std::FILE *file;
philpem@5 28790 do {
philpem@5 28791 cimg_std::sprintf(filename,"CImg_%.4u.bmp",snap_number++);
philpem@5 28792 if ((file=cimg_std::fopen(filename,"r"))!=0) cimg_std::fclose(file);
philpem@5 28793 } while (file);
philpem@5 28794 (+screen).draw_text(2,2,"Saving BMP snapshot...",black,gray,1,11).display(disp);
philpem@5 28795 screen.save(filename);
philpem@5 28796 screen.draw_text(2,2,"Snapshot '%s' saved.",black,gray,1,11,filename).display(disp);
philpem@5 28797 }
philpem@5 28798 disp.key = okey = 0;
philpem@5 28799 } break;
philpem@5 28800 }
philpem@5 28801
philpem@5 28802 // Handle mouse motion and mouse buttons
philpem@5 28803 if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) {
philpem@5 28804 visu.assign();
philpem@5 28805 if (disp.mouse_x>=0 && disp.mouse_y>=0) {
philpem@5 28806 const int
philpem@5 28807 mx = (mouse_x-16)*(int)whz/(disp.dimx()-32),
philpem@5 28808 cx = mx<0?0:(mx>=(int)whz?whz-1:mx),
philpem@5 28809 my = mouse_y-16,
philpem@5 28810 cy = my<=0?0:(my>=(disp.dimy()-32)?(disp.dimy()-32):my);
philpem@5 28811 if (button&1) { if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; }}
philpem@5 28812 else if (button&2) { if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; }}
philpem@5 28813 else if (obutton) { x1 = cx; y1 = y1>=0?cy:-1; selected = true; }
philpem@5 28814 } else if (!button && obutton) selected = true;
philpem@5 28815 obutton = button; omouse_x = mouse_x; omouse_y = mouse_y;
philpem@5 28816 }
philpem@5 28817 if (disp.is_resized) { disp.resize(false); visu0.assign(); }
philpem@5 28818 if (visu && visu0) disp.wait();
philpem@5 28819 }
philpem@5 28820 disp.normalization = onormalization;
philpem@5 28821 if (x1<x0) cimg::swap(x0,x1);
philpem@5 28822 if (y1<y0) cimg::swap(y0,y1);
philpem@5 28823 disp.key = okey;
philpem@5 28824 return CImg<intT>(4,1,1,1,x0,y0,x1,y1);
philpem@5 28825 }
philpem@5 28826
philpem@5 28827 //@}
philpem@5 28828 //---------------------------
philpem@5 28829 //
philpem@5 28830 //! \name Image File Loading
philpem@5 28831 //@{
philpem@5 28832 //---------------------------
philpem@5 28833
philpem@5 28834 //! Load an image from a file.
philpem@5 28835 /**
philpem@5 28836 \param filename is the name of the image file to load.
philpem@5 28837 \note The extension of \c filename defines the file format. If no filename
philpem@5 28838 extension is provided, CImg<T>::get_load() will try to load a .cimg file.
philpem@5 28839 **/
philpem@5 28840 CImg<T>& load(const char *const filename) {
philpem@5 28841 if (!filename)
philpem@5 28842 throw CImgArgumentException("CImg<%s>::load() : Cannot load (null) filename.",
philpem@5 28843 pixel_type());
philpem@5 28844 const char *ext = cimg::split_filename(filename);
philpem@5 28845 const unsigned int odebug = cimg::exception_mode();
philpem@5 28846 cimg::exception_mode() = 0;
philpem@5 28847 assign();
philpem@5 28848 try {
philpem@5 28849 #ifdef cimg_load_plugin
philpem@5 28850 cimg_load_plugin(filename);
philpem@5 28851 #endif
philpem@5 28852 #ifdef cimg_load_plugin1
philpem@5 28853 cimg_load_plugin1(filename);
philpem@5 28854 #endif
philpem@5 28855 #ifdef cimg_load_plugin2
philpem@5 28856 cimg_load_plugin2(filename);
philpem@5 28857 #endif
philpem@5 28858 #ifdef cimg_load_plugin3
philpem@5 28859 cimg_load_plugin3(filename);
philpem@5 28860 #endif
philpem@5 28861 #ifdef cimg_load_plugin4
philpem@5 28862 cimg_load_plugin4(filename);
philpem@5 28863 #endif
philpem@5 28864 #ifdef cimg_load_plugin5
philpem@5 28865 cimg_load_plugin5(filename);
philpem@5 28866 #endif
philpem@5 28867 #ifdef cimg_load_plugin6
philpem@5 28868 cimg_load_plugin6(filename);
philpem@5 28869 #endif
philpem@5 28870 #ifdef cimg_load_plugin7
philpem@5 28871 cimg_load_plugin7(filename);
philpem@5 28872 #endif
philpem@5 28873 #ifdef cimg_load_plugin8
philpem@5 28874 cimg_load_plugin8(filename);
philpem@5 28875 #endif
philpem@5 28876 // ASCII formats
philpem@5 28877 if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename);
philpem@5 28878 if (!cimg::strcasecmp(ext,"dlm") ||
philpem@5 28879 !cimg::strcasecmp(ext,"txt")) load_dlm(filename);
philpem@5 28880
philpem@5 28881 // 2D binary formats
philpem@5 28882 if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename);
philpem@5 28883 if (!cimg::strcasecmp(ext,"jpg") ||
philpem@5 28884 !cimg::strcasecmp(ext,"jpeg") ||
philpem@5 28885 !cimg::strcasecmp(ext,"jpe") ||
philpem@5 28886 !cimg::strcasecmp(ext,"jfif") ||
philpem@5 28887 !cimg::strcasecmp(ext,"jif")) load_jpeg(filename);
philpem@5 28888 if (!cimg::strcasecmp(ext,"png")) load_png(filename);
philpem@5 28889 if (!cimg::strcasecmp(ext,"ppm") ||
philpem@5 28890 !cimg::strcasecmp(ext,"pgm") ||
philpem@5 28891 !cimg::strcasecmp(ext,"pnm")) load_pnm(filename);
philpem@5 28892 if (!cimg::strcasecmp(ext,"tif") ||
philpem@5 28893 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
philpem@5 28894 if (!cimg::strcasecmp(ext,"cr2") ||
philpem@5 28895 !cimg::strcasecmp(ext,"crw") ||
philpem@5 28896 !cimg::strcasecmp(ext,"dcr") ||
philpem@5 28897 !cimg::strcasecmp(ext,"mrw") ||
philpem@5 28898 !cimg::strcasecmp(ext,"nef") ||
philpem@5 28899 !cimg::strcasecmp(ext,"orf") ||
philpem@5 28900 !cimg::strcasecmp(ext,"pix") ||
philpem@5 28901 !cimg::strcasecmp(ext,"ptx") ||
philpem@5 28902 !cimg::strcasecmp(ext,"raf") ||
philpem@5 28903 !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename);
philpem@5 28904
philpem@5 28905 // 3D binary formats
philpem@5 28906 if (!cimg::strcasecmp(ext,"dcm") ||
philpem@5 28907 !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename);
philpem@5 28908 if (!cimg::strcasecmp(ext,"hdr") ||
philpem@5 28909 !cimg::strcasecmp(ext,"nii")) load_analyze(filename);
philpem@5 28910 if (!cimg::strcasecmp(ext,"par") ||
philpem@5 28911 !cimg::strcasecmp(ext,"rec")) load_parrec(filename);
philpem@5 28912 if (!cimg::strcasecmp(ext,"inr")) load_inr(filename);
philpem@5 28913 if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename);
philpem@5 28914 if (!cimg::strcasecmp(ext,"cimg") ||
philpem@5 28915 !cimg::strcasecmp(ext,"cimgz") ||
philpem@5 28916 *ext=='\0') return load_cimg(filename);
philpem@5 28917
philpem@5 28918 // Archive files
philpem@5 28919 if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
philpem@5 28920
philpem@5 28921 // Image sequences
philpem@5 28922 if (!cimg::strcasecmp(ext,"avi") ||
philpem@5 28923 !cimg::strcasecmp(ext,"mov") ||
philpem@5 28924 !cimg::strcasecmp(ext,"asf") ||
philpem@5 28925 !cimg::strcasecmp(ext,"divx") ||
philpem@5 28926 !cimg::strcasecmp(ext,"flv") ||
philpem@5 28927 !cimg::strcasecmp(ext,"mpg") ||
philpem@5 28928 !cimg::strcasecmp(ext,"m1v") ||
philpem@5 28929 !cimg::strcasecmp(ext,"m2v") ||
philpem@5 28930 !cimg::strcasecmp(ext,"m4v") ||
philpem@5 28931 !cimg::strcasecmp(ext,"mjp") ||
philpem@5 28932 !cimg::strcasecmp(ext,"mkv") ||
philpem@5 28933 !cimg::strcasecmp(ext,"mpe") ||
philpem@5 28934 !cimg::strcasecmp(ext,"movie") ||
philpem@5 28935 !cimg::strcasecmp(ext,"ogm") ||
philpem@5 28936 !cimg::strcasecmp(ext,"qt") ||
philpem@5 28937 !cimg::strcasecmp(ext,"rm") ||
philpem@5 28938 !cimg::strcasecmp(ext,"vob") ||
philpem@5 28939 !cimg::strcasecmp(ext,"wmv") ||
philpem@5 28940 !cimg::strcasecmp(ext,"xvid") ||
philpem@5 28941 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
philpem@5 28942 if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
philpem@5 28943 } catch (CImgException& e) {
philpem@5 28944 if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
philpem@5 28945 cimg::exception_mode() = odebug;
philpem@5 28946 throw CImgIOException("CImg<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
philpem@5 28947 } else try {
philpem@5 28948 const char *const ftype = cimg::file_type(0,filename);
philpem@5 28949 assign();
philpem@5 28950 if (!cimg::strcmp(ftype,"pnm")) load_pnm(filename);
philpem@5 28951 if (!cimg::strcmp(ftype,"bmp")) load_bmp(filename);
philpem@5 28952 if (!cimg::strcmp(ftype,"jpeg")) load_jpeg(filename);
philpem@5 28953 if (!cimg::strcmp(ftype,"pan")) load_pandore(filename);
philpem@5 28954 if (!cimg::strcmp(ftype,"png")) load_png(filename);
philpem@5 28955 if (!cimg::strcmp(ftype,"tiff")) load_tiff(filename);
philpem@5 28956 if (is_empty()) throw CImgIOException("CImg<%s>::load()",pixel_type());
philpem@5 28957 } catch (CImgException&) {
philpem@5 28958 try {
philpem@5 28959 load_other(filename);
philpem@5 28960 } catch (CImgException&) {
philpem@5 28961 assign();
philpem@5 28962 }
philpem@5 28963 }
philpem@5 28964 }
philpem@5 28965 cimg::exception_mode() = odebug;
philpem@5 28966 if (is_empty())
philpem@5 28967 throw CImgIOException("CImg<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
philpem@5 28968 return *this;
philpem@5 28969 }
philpem@5 28970
philpem@5 28971 static CImg<T> get_load(const char *const filename) {
philpem@5 28972 return CImg<T>().load(filename);
philpem@5 28973 }
philpem@5 28974
philpem@5 28975 //! Load an image from an ASCII file.
philpem@5 28976 CImg<T>& load_ascii(const char *const filename) {
philpem@5 28977 return _load_ascii(0,filename);
philpem@5 28978 }
philpem@5 28979
philpem@5 28980 static CImg<T> get_load_ascii(const char *const filename) {
philpem@5 28981 return CImg<T>().load_ascii(filename);
philpem@5 28982 }
philpem@5 28983
philpem@5 28984 //! Load an image from an ASCII file.
philpem@5 28985 CImg<T>& load_ascii(cimg_std::FILE *const file) {
philpem@5 28986 return _load_ascii(file,0);
philpem@5 28987 }
philpem@5 28988
philpem@5 28989 static CImg<T> get_load_ascii(cimg_std::FILE *const file) {
philpem@5 28990 return CImg<T>().load_ascii(file);
philpem@5 28991 }
philpem@5 28992
philpem@5 28993 CImg<T>& _load_ascii(cimg_std::FILE *const file, const char *const filename) {
philpem@5 28994 if (!filename && !file)
philpem@5 28995 throw CImgArgumentException("CImg<%s>::load_ascii() : Cannot load (null) filename.",
philpem@5 28996 pixel_type());
philpem@5 28997 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 28998 char line[256] = { 0 };
philpem@5 28999 int err = cimg_std::fscanf(nfile,"%*[^0-9]%255[^\n]",line);
philpem@5 29000 unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1;
philpem@5 29001 cimg_std::sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dv);
philpem@5 29002 err = cimg_std::fscanf(nfile,"%*[^0-9.+-]");
philpem@5 29003 if (!dx || !dy || !dz || !dv) {
philpem@5 29004 if (!file) cimg::fclose(nfile);
philpem@5 29005 throw CImgIOException("CImg<%s>::load_ascii() : File '%s', invalid .ASC header, specified image dimensions are (%u,%u,%u,%u).",
philpem@5 29006 pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv);
philpem@5 29007 }
philpem@5 29008 assign(dx,dy,dz,dv);
philpem@5 29009 const unsigned long siz = size();
philpem@5 29010 double val;
philpem@5 29011 T *ptr = data;
philpem@5 29012 for (err = 1, off = 0; off<siz && err==1; ++off) {
philpem@5 29013 err = cimg_std::fscanf(nfile,"%lf%*[^0-9.+-]",&val);
philpem@5 29014 *(ptr++) = (T)val;
philpem@5 29015 }
philpem@5 29016 if (err!=1)
philpem@5 29017 cimg::warn("CImg<%s>::load_ascii() : File '%s', only %u/%lu values read.",
philpem@5 29018 pixel_type(),filename?filename:"(FILE*)",off-1,siz);
philpem@5 29019 if (!file) cimg::fclose(nfile);
philpem@5 29020 return *this;
philpem@5 29021 }
philpem@5 29022
philpem@5 29023 //! Load an image from a DLM file.
philpem@5 29024 CImg<T>& load_dlm(const char *const filename) {
philpem@5 29025 return _load_dlm(0,filename);
philpem@5 29026 }
philpem@5 29027
philpem@5 29028 static CImg<T> get_load_dlm(const char *const filename) {
philpem@5 29029 return CImg<T>().load_dlm(filename);
philpem@5 29030 }
philpem@5 29031
philpem@5 29032 //! Load an image from a DLM file.
philpem@5 29033 CImg<T>& load_dlm(cimg_std::FILE *const file) {
philpem@5 29034 return _load_dlm(file,0);
philpem@5 29035 }
philpem@5 29036
philpem@5 29037 static CImg<T> get_load_dlm(cimg_std::FILE *const file) {
philpem@5 29038 return CImg<T>().load_dlm(file);
philpem@5 29039 }
philpem@5 29040
philpem@5 29041 CImg<T>& _load_dlm(cimg_std::FILE *const file, const char *const filename) {
philpem@5 29042 if (!filename && !file)
philpem@5 29043 throw CImgArgumentException("CImg<%s>::load_dlm() : Cannot load (null) filename.",
philpem@5 29044 pixel_type());
philpem@5 29045 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
philpem@5 29046 assign(256,256);
philpem@5 29047 char c, delimiter[256] = { 0 }, tmp[256];
philpem@5 29048 unsigned int cdx = 0, dx = 0, dy = 0;
philpem@5 29049 int oerr = 0, err;
philpem@5 29050 double val;
philpem@5 29051 while ((err = cimg_std::fscanf(nfile,"%lf%255[^0-9.+-]",&val,delimiter))!=EOF) {
philpem@5 29052 oerr = err;
philpem@5 29053 if (err>0) (*this)(cdx++,dy) = (T)val;
philpem@5 29054 if (cdx>=width) resize(width+256,1,1,1,0);
philpem@5 29055 c = 0; if (!cimg_std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') {
philpem@5 29056 dx = cimg::max(cdx,dx);
philpem@5 29057 ++dy;
philpem@5 29058 if (dy>=height) resize(width,height+256,1,1,0);
philpem@5 29059 cdx = 0;
philpem@5 29060 }
philpem@5 29061 }
philpem@5 29062 if (cdx && oerr==1) { dx=cdx; ++dy; }
philpem@5 29063 if (!dx || !dy) {
philpem@5 29064 if (!file) cimg::fclose(nfile);
philpem@5 29065 throw CImgIOException("CImg<%s>::load_dlm() : File '%s', invalid DLM file, specified image dimensions are (%u,%u).",
philpem@5 29066 pixel_type(),filename?filename:"(FILE*)",dx,dy);
philpem@5 29067 }
philpem@5 29068 resize(dx,dy,1,1,0);
philpem@5 29069 if (!file) cimg::fclose(nfile);
philpem@5 29070 return *this;
philpem@5 29071 }
philpem@5 29072
philpem@5 29073 //! Load an image from a BMP file.
philpem@5 29074 CImg<T>& load_bmp(const char *const filename) {
philpem@5 29075 return _load_bmp(0,filename);
philpem@5 29076 }
philpem@5 29077
philpem@5 29078 static CImg<T> get_load_bmp(const char *const filename) {
philpem@5 29079 return CImg<T>().load_bmp(filename);
philpem@5 29080 }
philpem@5 29081
philpem@5 29082 //! Load an image from a BMP file.
philpem@5 29083 CImg<T>& load_bmp(cimg_std::FILE *const file) {
philpem@5 29084 return _load_bmp(file,0);
philpem@5 29085 }
philpem@5 29086
philpem@5 29087 static CImg<T> get_load_bmp(cimg_std::FILE *const file) {
philpem@5 29088 return CImg<T>().load_bmp(file);
philpem@5 29089 }
philpem@5 29090
philpem@5 29091 CImg<T>& _load_bmp(cimg_std::FILE *const file, const char *const filename) {
philpem@5 29092 if (!filename && !file)
philpem@5 29093 throw CImgArgumentException("CImg<%s>::load_bmp() : Cannot load (null) filename.",
philpem@5 29094 pixel_type());
philpem@5 29095 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 29096 unsigned char header[64];
philpem@5 29097 cimg::fread(header,54,nfile);
philpem@5 29098 if (header[0]!='B' || header[1]!='M') {
philpem@5 29099 if (!file) cimg::fclose(nfile);
philpem@5 29100 throw CImgIOException("CImg<%s>::load_bmp() : Invalid valid BMP file (filename '%s').",
philpem@5 29101 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29102 }
philpem@5 29103 assign();
philpem@5 29104
philpem@5 29105 // Read header and pixel buffer
philpem@5 29106 int
philpem@5 29107 file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24),
philpem@5 29108 offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24),
philpem@5 29109 dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24),
philpem@5 29110 dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24),
philpem@5 29111 compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24),
philpem@5 29112 nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24),
philpem@5 29113 bpp = header[0x1C] + (header[0x1D]<<8),
philpem@5 29114 *palette = 0;
philpem@5 29115 const int
philpem@5 29116 dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)),
philpem@5 29117 align = (4-dx_bytes%4)%4,
philpem@5 29118 buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset);
philpem@5 29119
philpem@5 29120 if (bpp<16) { if (!nb_colors) nb_colors=1<<bpp; } else nb_colors = 0;
philpem@5 29121 if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); }
philpem@5 29122 const int xoffset = offset-54-4*nb_colors;
philpem@5 29123 if (xoffset>0) cimg_std::fseek(nfile,xoffset,SEEK_CUR);
philpem@5 29124 unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer;
philpem@5 29125 cimg::fread(buffer,buf_size,nfile);
philpem@5 29126 if (!file) cimg::fclose(nfile);
philpem@5 29127
philpem@5 29128 // Decompress buffer (if necessary)
philpem@5 29129 if (compression) {
philpem@5 29130 delete[] buffer;
philpem@5 29131 if (file) {
philpem@5 29132 throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",
philpem@5 29133 pixel_type());
philpem@5 29134 } else return load_other(filename);
philpem@5 29135 }
philpem@5 29136
philpem@5 29137 // Read pixel data
philpem@5 29138 assign(dx,cimg::abs(dy),1,3);
philpem@5 29139 switch (bpp) {
philpem@5 29140 case 1 : { // Monochrome
philpem@5 29141 for (int y=height-1; y>=0; --y) {
philpem@5 29142 unsigned char mask = 0x80, val = 0;
philpem@5 29143 cimg_forX(*this,x) {
philpem@5 29144 if (mask==0x80) val = *(ptrs++);
philpem@5 29145 const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0));
philpem@5 29146 (*this)(x,y,2) = (T)*(col++);
philpem@5 29147 (*this)(x,y,1) = (T)*(col++);
philpem@5 29148 (*this)(x,y,0) = (T)*(col++);
philpem@5 29149 mask = cimg::ror(mask);
philpem@5 29150 } ptrs+=align; }
philpem@5 29151 } break;
philpem@5 29152 case 4 : { // 16 colors
philpem@5 29153 for (int y=height-1; y>=0; --y) {
philpem@5 29154 unsigned char mask = 0xF0, val = 0;
philpem@5 29155 cimg_forX(*this,x) {
philpem@5 29156 if (mask==0xF0) val = *(ptrs++);
philpem@5 29157 const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4));
philpem@5 29158 unsigned char *col = (unsigned char*)(palette+color);
philpem@5 29159 (*this)(x,y,2) = (T)*(col++);
philpem@5 29160 (*this)(x,y,1) = (T)*(col++);
philpem@5 29161 (*this)(x,y,0) = (T)*(col++);
philpem@5 29162 mask = cimg::ror(mask,4);
philpem@5 29163 } ptrs+=align; }
philpem@5 29164 } break;
philpem@5 29165 case 8 : { // 256 colors
philpem@5 29166 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
philpem@5 29167 const unsigned char *col = (unsigned char*)(palette+*(ptrs++));
philpem@5 29168 (*this)(x,y,2) = (T)*(col++);
philpem@5 29169 (*this)(x,y,1) = (T)*(col++);
philpem@5 29170 (*this)(x,y,0) = (T)*(col++);
philpem@5 29171 } ptrs+=align; }
philpem@5 29172 } break;
philpem@5 29173 case 16 : { // 16 bits colors
philpem@5 29174 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
philpem@5 29175 const unsigned char c1 = *(ptrs++), c2 = *(ptrs++);
philpem@5 29176 const unsigned short col = (unsigned short)(c1|(c2<<8));
philpem@5 29177 (*this)(x,y,2) = (T)(col&0x1F);
philpem@5 29178 (*this)(x,y,1) = (T)((col>>5)&0x1F);
philpem@5 29179 (*this)(x,y,0) = (T)((col>>10)&0x1F);
philpem@5 29180 } ptrs+=align; }
philpem@5 29181 } break;
philpem@5 29182 case 24 : { // 24 bits colors
philpem@5 29183 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
philpem@5 29184 (*this)(x,y,2) = (T)*(ptrs++);
philpem@5 29185 (*this)(x,y,1) = (T)*(ptrs++);
philpem@5 29186 (*this)(x,y,0) = (T)*(ptrs++);
philpem@5 29187 } ptrs+=align; }
philpem@5 29188 } break;
philpem@5 29189 case 32 : { // 32 bits colors
philpem@5 29190 for (int y=height-1; y>=0; --y) { cimg_forX(*this,x) {
philpem@5 29191 (*this)(x,y,2) = (T)*(ptrs++);
philpem@5 29192 (*this)(x,y,1) = (T)*(ptrs++);
philpem@5 29193 (*this)(x,y,0) = (T)*(ptrs++);
philpem@5 29194 ++ptrs;
philpem@5 29195 } ptrs+=align; }
philpem@5 29196 } break;
philpem@5 29197 }
philpem@5 29198 if (palette) delete[] palette;
philpem@5 29199 delete[] buffer;
philpem@5 29200 if (dy<0) mirror('y');
philpem@5 29201 return *this;
philpem@5 29202 }
philpem@5 29203
philpem@5 29204 //! Load an image from a JPEG file.
philpem@5 29205 CImg<T>& load_jpeg(const char *const filename) {
philpem@5 29206 return _load_jpeg(0,filename);
philpem@5 29207 }
philpem@5 29208
philpem@5 29209 static CImg<T> get_load_jpeg(const char *const filename) {
philpem@5 29210 return CImg<T>().load_jpeg(filename);
philpem@5 29211 }
philpem@5 29212
philpem@5 29213 //! Load an image from a JPEG file.
philpem@5 29214 CImg<T>& load_jpeg(cimg_std::FILE *const file) {
philpem@5 29215 return _load_jpeg(file,0);
philpem@5 29216 }
philpem@5 29217
philpem@5 29218 static CImg<T> get_load_jpeg(cimg_std::FILE *const file) {
philpem@5 29219 return CImg<T>().load_jpeg(file);
philpem@5 29220 }
philpem@5 29221
philpem@5 29222 CImg<T>& _load_jpeg(cimg_std::FILE *const file, const char *const filename) {
philpem@5 29223 if (!filename && !file)
philpem@5 29224 throw CImgArgumentException("CImg<%s>::load_jpeg() : Cannot load (null) filename.",
philpem@5 29225 pixel_type());
philpem@5 29226 #ifndef cimg_use_jpeg
philpem@5 29227 if (file)
philpem@5 29228 throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.",
philpem@5 29229 pixel_type());
philpem@5 29230 else return load_other(filename);
philpem@5 29231 #else
philpem@5 29232 struct jpeg_decompress_struct cinfo;
philpem@5 29233 struct jpeg_error_mgr jerr;
philpem@5 29234 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 29235
philpem@5 29236 cinfo.err = jpeg_std_error(&jerr);
philpem@5 29237 jpeg_create_decompress(&cinfo);
philpem@5 29238 jpeg_stdio_src(&cinfo,nfile);
philpem@5 29239 jpeg_read_header(&cinfo,TRUE);
philpem@5 29240 jpeg_start_decompress(&cinfo);
philpem@5 29241
philpem@5 29242 if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) {
philpem@5 29243 cimg::warn("CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert",
philpem@5 29244 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29245 if (!file) return load_other(filename);
philpem@5 29246 else {
philpem@5 29247 if (!file) cimg::fclose(nfile);
philpem@5 29248 throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.",
philpem@5 29249 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29250 }
philpem@5 29251 }
philpem@5 29252
philpem@5 29253 const unsigned int row_stride = cinfo.output_width * cinfo.output_components;
philpem@5 29254 unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf;
philpem@5 29255 JSAMPROW row_pointer[1];
philpem@5 29256 while (cinfo.output_scanline < cinfo.output_height) {
philpem@5 29257 row_pointer[0] = &buf[cinfo.output_scanline*row_stride];
philpem@5 29258 jpeg_read_scanlines(&cinfo,row_pointer,1);
philpem@5 29259 }
philpem@5 29260 jpeg_finish_decompress(&cinfo);
philpem@5 29261 jpeg_destroy_decompress(&cinfo);
philpem@5 29262 if (!file) cimg::fclose(nfile);
philpem@5 29263
philpem@5 29264 assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components);
philpem@5 29265 switch (dim) {
philpem@5 29266 case 1 : {
philpem@5 29267 T *ptr_g = data;
philpem@5 29268 cimg_forXY(*this,x,y) *(ptr_g++) = (T)*(buf2++);
philpem@5 29269 } break;
philpem@5 29270 case 3 : {
philpem@5 29271 T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
philpem@5 29272 cimg_forXY(*this,x,y) {
philpem@5 29273 *(ptr_r++) = (T)*(buf2++);
philpem@5 29274 *(ptr_g++) = (T)*(buf2++);
philpem@5 29275 *(ptr_b++) = (T)*(buf2++);
philpem@5 29276 }
philpem@5 29277 } break;
philpem@5 29278 case 4 : {
philpem@5 29279 T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1),
philpem@5 29280 *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
philpem@5 29281 cimg_forXY(*this,x,y) {
philpem@5 29282 *(ptr_r++) = (T)*(buf2++);
philpem@5 29283 *(ptr_g++) = (T)*(buf2++);
philpem@5 29284 *(ptr_b++) = (T)*(buf2++);
philpem@5 29285 *(ptr_a++) = (T)*(buf2++);
philpem@5 29286 }
philpem@5 29287 } break;
philpem@5 29288 }
philpem@5 29289 delete[] buf;
philpem@5 29290 return *this;
philpem@5 29291 #endif
philpem@5 29292 }
philpem@5 29293
philpem@5 29294 //! Load an image from a file, using Magick++ library.
philpem@5 29295 // Added April/may 2006 by Christoph Hormann <chris_hormann@gmx.de>
philpem@5 29296 // This is experimental code, not much tested, use with care.
philpem@5 29297 CImg<T>& load_magick(const char *const filename) {
philpem@5 29298 if (!filename)
philpem@5 29299 throw CImgArgumentException("CImg<%s>::load_magick() : Cannot load (null) filename.",
philpem@5 29300 pixel_type());
philpem@5 29301 #ifdef cimg_use_magick
philpem@5 29302 Magick::Image image(filename);
philpem@5 29303 const unsigned int W = image.size().width(), H = image.size().height();
philpem@5 29304 switch (image.type()) {
philpem@5 29305 case Magick::PaletteMatteType :
philpem@5 29306 case Magick::TrueColorMatteType :
philpem@5 29307 case Magick::ColorSeparationType : {
philpem@5 29308 assign(W,H,1,4);
philpem@5 29309 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2), *adata = ptr(0,0,0,3);
philpem@5 29310 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
philpem@5 29311 for (unsigned int off = W*H; off; --off) {
philpem@5 29312 *(rdata++) = (T)(pixels->red);
philpem@5 29313 *(gdata++) = (T)(pixels->green);
philpem@5 29314 *(bdata++) = (T)(pixels->blue);
philpem@5 29315 *(adata++) = (T)(pixels->opacity);
philpem@5 29316 ++pixels;
philpem@5 29317 }
philpem@5 29318 } break;
philpem@5 29319 case Magick::PaletteType :
philpem@5 29320 case Magick::TrueColorType : {
philpem@5 29321 assign(W,H,1,3);
philpem@5 29322 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
philpem@5 29323 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
philpem@5 29324 for (unsigned int off = W*H; off; --off) {
philpem@5 29325 *(rdata++) = (T)(pixels->red);
philpem@5 29326 *(gdata++) = (T)(pixels->green);
philpem@5 29327 *(bdata++) = (T)(pixels->blue);
philpem@5 29328 ++pixels;
philpem@5 29329 }
philpem@5 29330 } break;
philpem@5 29331 case Magick::GrayscaleMatteType : {
philpem@5 29332 assign(W,H,1,2);
philpem@5 29333 T *data = ptr(0,0,0,0), *adata = ptr(0,0,0,1);
philpem@5 29334 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
philpem@5 29335 for (unsigned int off = W*H; off; --off) {
philpem@5 29336 *(data++) = (T)(pixels->red);
philpem@5 29337 *(adata++) = (T)(pixels->opacity);
philpem@5 29338 ++pixels;
philpem@5 29339 }
philpem@5 29340 } break;
philpem@5 29341 default : {
philpem@5 29342 assign(W,H,1,1);
philpem@5 29343 T *data = ptr(0,0,0,0);
philpem@5 29344 Magick::PixelPacket *pixels = image.getPixels(0,0,W,H);
philpem@5 29345 for (unsigned int off = W*H; off; --off) {
philpem@5 29346 *(data++) = (T)(pixels->red);
philpem@5 29347 ++pixels;
philpem@5 29348 }
philpem@5 29349 }
philpem@5 29350 }
philpem@5 29351 #else
philpem@5 29352 throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ library has not been linked.",
philpem@5 29353 pixel_type(),filename);
philpem@5 29354 #endif
philpem@5 29355 return *this;
philpem@5 29356 }
philpem@5 29357
philpem@5 29358 static CImg<T> get_load_magick(const char *const filename) {
philpem@5 29359 return CImg<T>().load_magick(filename);
philpem@5 29360 }
philpem@5 29361
philpem@5 29362 //! Load an image from a PNG file.
philpem@5 29363 CImg<T>& load_png(const char *const filename) {
philpem@5 29364 return _load_png(0,filename);
philpem@5 29365 }
philpem@5 29366
philpem@5 29367 static CImg<T> get_load_png(const char *const filename) {
philpem@5 29368 return CImg<T>().load_png(filename);
philpem@5 29369 }
philpem@5 29370
philpem@5 29371 //! Load an image from a PNG file.
philpem@5 29372 CImg<T>& load_png(cimg_std::FILE *const file) {
philpem@5 29373 return _load_png(file,0);
philpem@5 29374 }
philpem@5 29375
philpem@5 29376 static CImg<T> get_load_png(cimg_std::FILE *const file) {
philpem@5 29377 return CImg<T>().load_png(file);
philpem@5 29378 }
philpem@5 29379
philpem@5 29380 // (Note : Most of this function has been written by Eric Fausett)
philpem@5 29381 CImg<T>& _load_png(cimg_std::FILE *const file, const char *const filename) {
philpem@5 29382 if (!filename && !file)
philpem@5 29383 throw CImgArgumentException("CImg<%s>::load_png() : Cannot load (null) filename.",
philpem@5 29384 pixel_type());
philpem@5 29385 #ifndef cimg_use_png
philpem@5 29386 if (file)
philpem@5 29387 throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",
philpem@5 29388 pixel_type());
philpem@5 29389 else return load_other(filename);
philpem@5 29390 #else
philpem@5 29391 // Open file and check for PNG validity
philpem@5 29392 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
philpem@5 29393 cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb");
philpem@5 29394
philpem@5 29395 unsigned char pngCheck[8];
philpem@5 29396 cimg::fread(pngCheck,8,(cimg_std::FILE*)nfile);
philpem@5 29397 if (png_sig_cmp(pngCheck,0,8)) {
philpem@5 29398 if (!file) cimg::fclose(nfile);
philpem@5 29399 throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.",
philpem@5 29400 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 29401 }
philpem@5 29402
philpem@5 29403 // Setup PNG structures for read
philpem@5 29404 png_voidp user_error_ptr = 0;
philpem@5 29405 png_error_ptr user_error_fn = 0, user_warning_fn = 0;
philpem@5 29406 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn);
philpem@5 29407 if (!png_ptr) {
philpem@5 29408 if (!file) cimg::fclose(nfile);
philpem@5 29409 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.",
philpem@5 29410 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 29411 }
philpem@5 29412 png_infop info_ptr = png_create_info_struct(png_ptr);
philpem@5 29413 if (!info_ptr) {
philpem@5 29414 if (!file) cimg::fclose(nfile);
philpem@5 29415 png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0);
philpem@5 29416 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.",
philpem@5 29417 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 29418 }
philpem@5 29419 png_infop end_info = png_create_info_struct(png_ptr);
philpem@5 29420 if (!end_info) {
philpem@5 29421 if (!file) cimg::fclose(nfile);
philpem@5 29422 png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0);
philpem@5 29423 throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.",
philpem@5 29424 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 29425 }
philpem@5 29426
philpem@5 29427 // Error handling callback for png file reading
philpem@5 29428 if (setjmp(png_jmpbuf(png_ptr))) {
philpem@5 29429 if (!file) cimg::fclose((cimg_std::FILE*)nfile);
philpem@5 29430 png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
philpem@5 29431 throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.",
philpem@5 29432 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 29433 }
philpem@5 29434 png_init_io(png_ptr, nfile);
philpem@5 29435 png_set_sig_bytes(png_ptr, 8);
philpem@5 29436
philpem@5 29437 // Get PNG Header Info up to data block
philpem@5 29438 png_read_info(png_ptr,info_ptr);
philpem@5 29439 png_uint_32 W, H;
philpem@5 29440 int bit_depth, color_type, interlace_type;
philpem@5 29441 png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,int_p_NULL,int_p_NULL);
philpem@5 29442 int new_bit_depth = bit_depth;
philpem@5 29443 int new_color_type = color_type;
philpem@5 29444
philpem@5 29445 // Transforms to unify image data
philpem@5 29446 if (new_color_type == PNG_COLOR_TYPE_PALETTE){
philpem@5 29447 png_set_palette_to_rgb(png_ptr);
philpem@5 29448 new_color_type -= PNG_COLOR_MASK_PALETTE;
philpem@5 29449 new_bit_depth = 8;
philpem@5 29450 }
philpem@5 29451 if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){
philpem@5 29452 png_set_gray_1_2_4_to_8(png_ptr);
philpem@5 29453 new_bit_depth = 8;
philpem@5 29454 }
philpem@5 29455 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
philpem@5 29456 png_set_tRNS_to_alpha(png_ptr);
philpem@5 29457 if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){
philpem@5 29458 png_set_gray_to_rgb(png_ptr);
philpem@5 29459 new_color_type |= PNG_COLOR_MASK_COLOR;
philpem@5 29460 }
philpem@5 29461 if (new_color_type == PNG_COLOR_TYPE_RGB)
philpem@5 29462 png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER);
philpem@5 29463 png_read_update_info(png_ptr,info_ptr);
philpem@5 29464 if (!(new_bit_depth==8 || new_bit_depth==16)) {
philpem@5 29465 if (!file) cimg::fclose(nfile);
philpem@5 29466 png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0);
philpem@5 29467 throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)",
philpem@5 29468 pixel_type(),nfilename?nfilename:"(FILE*)",new_bit_depth);
philpem@5 29469 }
philpem@5 29470 const int byte_depth = new_bit_depth>>3;
philpem@5 29471
philpem@5 29472 // Allocate Memory for Image Read
philpem@5 29473 png_bytep *imgData = new png_bytep[H];
philpem@5 29474 for (unsigned int row = 0; row<H; ++row) imgData[row] = new png_byte[byte_depth*4*W];
philpem@5 29475 png_read_image(png_ptr,imgData);
philpem@5 29476 png_read_end(png_ptr,end_info);
philpem@5 29477
philpem@5 29478 // Read pixel data
philpem@5 29479 if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) {
philpem@5 29480 if (!file) cimg::fclose(nfile);
philpem@5 29481 png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0);
philpem@5 29482 throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)",
philpem@5 29483 pixel_type(),nfilename?nfilename:"(FILE*)",new_color_type);
philpem@5 29484 }
philpem@5 29485 const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB);
philpem@5 29486 assign(W,H,1,no_alpha_channel?3:4);
philpem@5 29487 T *ptr1 = ptr(0,0,0,0), *ptr2 = ptr(0,0,0,1), *ptr3 = ptr(0,0,0,2), *ptr4 = ptr(0,0,0,3);
philpem@5 29488 switch (new_bit_depth) {
philpem@5 29489 case 8 : {
philpem@5 29490 cimg_forY(*this,y){
philpem@5 29491 const unsigned char *ptrs = (unsigned char*)imgData[y];
philpem@5 29492 cimg_forX(*this,x){
philpem@5 29493 *(ptr1++) = (T)*(ptrs++);
philpem@5 29494 *(ptr2++) = (T)*(ptrs++);
philpem@5 29495 *(ptr3++) = (T)*(ptrs++);
philpem@5 29496 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
philpem@5 29497 }
philpem@5 29498 }
philpem@5 29499 } break;
philpem@5 29500 case 16 : {
philpem@5 29501 cimg_forY(*this,y){
philpem@5 29502 const unsigned short *ptrs = (unsigned short*)(imgData[y]);
philpem@5 29503 if (!cimg::endianness()) cimg::invert_endianness(ptrs,4*width);
philpem@5 29504 cimg_forX(*this,x){
philpem@5 29505 *(ptr1++) = (T)*(ptrs++);
philpem@5 29506 *(ptr2++) = (T)*(ptrs++);
philpem@5 29507 *(ptr3++) = (T)*(ptrs++);
philpem@5 29508 if (no_alpha_channel) ++ptrs; else *(ptr4++) = (T)*(ptrs++);
philpem@5 29509 }
philpem@5 29510 }
philpem@5 29511 } break;
philpem@5 29512 }
philpem@5 29513 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
philpem@5 29514
philpem@5 29515 // Deallocate Image Read Memory
philpem@5 29516 cimg_forY(*this,n) delete[] imgData[n];
philpem@5 29517 delete[] imgData;
philpem@5 29518 if (!file) cimg::fclose(nfile);
philpem@5 29519 return *this;
philpem@5 29520 #endif
philpem@5 29521 }
philpem@5 29522
philpem@5 29523 //! Load an image from a PNM file.
philpem@5 29524 CImg<T>& load_pnm(const char *const filename) {
philpem@5 29525 return _load_pnm(0,filename);
philpem@5 29526 }
philpem@5 29527
philpem@5 29528 static CImg<T> get_load_pnm(const char *const filename) {
philpem@5 29529 return CImg<T>().load_pnm(filename);
philpem@5 29530 }
philpem@5 29531
philpem@5 29532 //! Load an image from a PNM file.
philpem@5 29533 CImg<T>& load_pnm(cimg_std::FILE *const file) {
philpem@5 29534 return _load_pnm(file,0);
philpem@5 29535 }
philpem@5 29536
philpem@5 29537 static CImg<T> get_load_pnm(cimg_std::FILE *const file) {
philpem@5 29538 return CImg<T>().load_pnm(file);
philpem@5 29539 }
philpem@5 29540
philpem@5 29541 CImg<T>& _load_pnm(cimg_std::FILE *const file, const char *const filename) {
philpem@5 29542 if (!filename && !file)
philpem@5 29543 throw CImgArgumentException("CImg<%s>::load_pnm() : Cannot load (null) filename.",
philpem@5 29544 pixel_type());
philpem@5 29545 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 29546 unsigned int ppm_type, W, H, colormax = 255;
philpem@5 29547 char item[1024] = { 0 };
philpem@5 29548 int err, rval, gval, bval;
philpem@5 29549 const int cimg_iobuffer = 12*1024*1024;
philpem@5 29550 while ((err=cimg_std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
philpem@5 29551 if (cimg_std::sscanf(item," P%u",&ppm_type)!=1) {
philpem@5 29552 if (!file) cimg::fclose(nfile);
philpem@5 29553 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.",
philpem@5 29554 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29555 }
philpem@5 29556 while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
philpem@5 29557 if ((err=cimg_std::sscanf(item," %u %u %u",&W,&H,&colormax))<2) {
philpem@5 29558 if (!file) cimg::fclose(nfile);
philpem@5 29559 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.",
philpem@5 29560 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29561 }
philpem@5 29562 if (err==2) {
philpem@5 29563 while ((err=cimg_std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) cimg_std::fgetc(nfile);
philpem@5 29564 if (cimg_std::sscanf(item,"%u",&colormax)!=1)
philpem@5 29565 cimg::warn("CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.",
philpem@5 29566 pixel_type(),filename?filename:"(FILE*)");
philpem@5 29567 }
philpem@5 29568 cimg_std::fgetc(nfile);
philpem@5 29569 assign();
philpem@5 29570
philpem@5 29571 switch (ppm_type) {
philpem@5 29572 case 2 : { // Grey Ascii
philpem@5 29573 assign(W,H,1,1);
philpem@5 29574 T* rdata = data;
philpem@5 29575 cimg_foroff(*this,off) { if (cimg_std::fscanf(nfile,"%d",&rval)>0) *(rdata++) = (T)rval; else break; }
philpem@5 29576 } break;
philpem@5 29577 case 3 : { // Color Ascii
philpem@5 29578 assign(W,H,1,3);
philpem@5 29579 T *rdata = ptr(0,0,0,0), *gdata = ptr(0,0,0,1), *bdata = ptr(0,0,0,2);
philpem@5 29580 cimg_forXY(*this,x,y) {
philpem@5 29581 if (cimg_std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { *(rdata++) = (T)rval; *(gdata++) = (T)gval; *(bdata++) = (T)bval; }
philpem@5 29582 else break;
philpem@5 29583 }
philpem@5 29584 } break;
philpem@5 29585 case 5 : { // Grey Binary
philpem@5 29586 if (colormax<256) { // 8 bits
philpem@5 29587 CImg<ucharT> raw;
philpem@5 29588 assign(W,H,1,1);
philpem@5 29589 T *ptrd = ptr(0,0,0,0);
philpem@5 29590 for (int toread = (int)size(); toread>0; ) {
philpem@5 29591 raw.assign(cimg::min(toread,cimg_iobuffer));
philpem@5 29592 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29593 toread-=raw.width;
philpem@5 29594 const unsigned char *ptrs = raw.data;
philpem@5 29595 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
philpem@5 29596 }
philpem@5 29597 } else { // 16 bits
philpem@5 29598 CImg<ushortT> raw;
philpem@5 29599 assign(W,H,1,1);
philpem@5 29600 T *ptrd = ptr(0,0,0,0);
philpem@5 29601 for (int toread = (int)size(); toread>0; ) {
philpem@5 29602 raw.assign(cimg::min(toread,cimg_iobuffer/2));
philpem@5 29603 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29604 if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
philpem@5 29605 toread-=raw.width;
philpem@5 29606 const unsigned short *ptrs = raw.data;
philpem@5 29607 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++);
philpem@5 29608 }
philpem@5 29609 }
philpem@5 29610 } break;
philpem@5 29611 case 6 : { // Color Binary
philpem@5 29612 if (colormax<256) { // 8 bits
philpem@5 29613 CImg<ucharT> raw;
philpem@5 29614 assign(W,H,1,3);
philpem@5 29615 T
philpem@5 29616 *ptr_r = ptr(0,0,0,0),
philpem@5 29617 *ptr_g = ptr(0,0,0,1),
philpem@5 29618 *ptr_b = ptr(0,0,0,2);
philpem@5 29619 for (int toread = (int)size(); toread>0; ) {
philpem@5 29620 raw.assign(cimg::min(toread,cimg_iobuffer));
philpem@5 29621 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29622 toread-=raw.width;
philpem@5 29623 const unsigned char *ptrs = raw.data;
philpem@5 29624 for (unsigned int off = raw.width/3; off; --off) {
philpem@5 29625 *(ptr_r++) = (T)*(ptrs++);
philpem@5 29626 *(ptr_g++) = (T)*(ptrs++);
philpem@5 29627 *(ptr_b++) = (T)*(ptrs++);
philpem@5 29628 }
philpem@5 29629 }
philpem@5 29630 } else { // 16 bits
philpem@5 29631 CImg<ushortT> raw;
philpem@5 29632 assign(W,H,1,3);
philpem@5 29633 T
philpem@5 29634 *ptr_r = ptr(0,0,0,0),
philpem@5 29635 *ptr_g = ptr(0,0,0,1),
philpem@5 29636 *ptr_b = ptr(0,0,0,2);
philpem@5 29637 for (int toread = (int)size(); toread>0; ) {
philpem@5 29638 raw.assign(cimg::min(toread,cimg_iobuffer/2));
philpem@5 29639 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29640 if (!cimg::endianness()) cimg::invert_endianness(raw.data,raw.width);
philpem@5 29641 toread-=raw.width;
philpem@5 29642 const unsigned short *ptrs = raw.data;
philpem@5 29643 for (unsigned int off = raw.width/3; off; --off) {
philpem@5 29644 *(ptr_r++) = (T)*(ptrs++);
philpem@5 29645 *(ptr_g++) = (T)*(ptrs++);
philpem@5 29646 *(ptr_b++) = (T)*(ptrs++);
philpem@5 29647 }
philpem@5 29648 }
philpem@5 29649 }
philpem@5 29650 } break;
philpem@5 29651 default :
philpem@5 29652 if (!file) cimg::fclose(nfile);
philpem@5 29653 throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.",
philpem@5 29654 pixel_type(),filename?filename:"(FILE*)",ppm_type);
philpem@5 29655 }
philpem@5 29656 if (!file) cimg::fclose(nfile);
philpem@5 29657 return *this;
philpem@5 29658 }
philpem@5 29659
philpem@5 29660 //! Load an image from a RGB file.
philpem@5 29661 CImg<T>& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29662 return _load_rgb(0,filename,dimw,dimh);
philpem@5 29663 }
philpem@5 29664
philpem@5 29665 static CImg<T> get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29666 return CImg<T>().load_rgb(filename,dimw,dimh);
philpem@5 29667 }
philpem@5 29668
philpem@5 29669 //! Load an image from a RGB file.
philpem@5 29670 CImg<T>& load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29671 return _load_rgb(file,0,dimw,dimh);
philpem@5 29672 }
philpem@5 29673
philpem@5 29674 static CImg<T> get_load_rgb(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29675 return CImg<T>().load_rgb(file,dimw,dimh);
philpem@5 29676 }
philpem@5 29677
philpem@5 29678 CImg<T>& _load_rgb(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
philpem@5 29679 if (!filename && !file)
philpem@5 29680 throw CImgArgumentException("CImg<%s>::load_rgb() : Cannot load (null) filename.",
philpem@5 29681 pixel_type());
philpem@5 29682 if (!dimw || !dimh) return assign();
philpem@5 29683 const int cimg_iobuffer = 12*1024*1024;
philpem@5 29684 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 29685 CImg<ucharT> raw;
philpem@5 29686 assign(dimw,dimh,1,3);
philpem@5 29687 T
philpem@5 29688 *ptr_r = ptr(0,0,0,0),
philpem@5 29689 *ptr_g = ptr(0,0,0,1),
philpem@5 29690 *ptr_b = ptr(0,0,0,2);
philpem@5 29691 for (int toread = (int)size(); toread>0; ) {
philpem@5 29692 raw.assign(cimg::min(toread,cimg_iobuffer));
philpem@5 29693 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29694 toread-=raw.width;
philpem@5 29695 const unsigned char *ptrs = raw.data;
philpem@5 29696 for (unsigned int off = raw.width/3; off; --off) {
philpem@5 29697 *(ptr_r++) = (T)*(ptrs++);
philpem@5 29698 *(ptr_g++) = (T)*(ptrs++);
philpem@5 29699 *(ptr_b++) = (T)*(ptrs++);
philpem@5 29700 }
philpem@5 29701 }
philpem@5 29702 if (!file) cimg::fclose(nfile);
philpem@5 29703 return *this;
philpem@5 29704 }
philpem@5 29705
philpem@5 29706 //! Load an image from a RGBA file.
philpem@5 29707 CImg<T>& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29708 return _load_rgba(0,filename,dimw,dimh);
philpem@5 29709 }
philpem@5 29710
philpem@5 29711 static CImg<T> get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29712 return CImg<T>().load_rgba(filename,dimw,dimh);
philpem@5 29713 }
philpem@5 29714
philpem@5 29715 //! Load an image from a RGBA file.
philpem@5 29716 CImg<T>& load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29717 return _load_rgba(file,0,dimw,dimh);
philpem@5 29718 }
philpem@5 29719
philpem@5 29720 static CImg<T> get_load_rgba(cimg_std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) {
philpem@5 29721 return CImg<T>().load_rgba(file,dimw,dimh);
philpem@5 29722 }
philpem@5 29723
philpem@5 29724 CImg<T>& _load_rgba(cimg_std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) {
philpem@5 29725 if (!filename && !file)
philpem@5 29726 throw CImgArgumentException("CImg<%s>::load_rgba() : Cannot load (null) filename.",
philpem@5 29727 pixel_type());
philpem@5 29728 if (!dimw || !dimh) return assign();
philpem@5 29729 const int cimg_iobuffer = 12*1024*1024;
philpem@5 29730 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 29731 CImg<ucharT> raw;
philpem@5 29732 assign(dimw,dimh,1,4);
philpem@5 29733 T
philpem@5 29734 *ptr_r = ptr(0,0,0,0),
philpem@5 29735 *ptr_g = ptr(0,0,0,1),
philpem@5 29736 *ptr_b = ptr(0,0,0,2),
philpem@5 29737 *ptr_a = ptr(0,0,0,3);
philpem@5 29738 for (int toread = (int)size(); toread>0; ) {
philpem@5 29739 raw.assign(cimg::min(toread,cimg_iobuffer));
philpem@5 29740 cimg::fread(raw.data,raw.width,nfile);
philpem@5 29741 toread-=raw.width;
philpem@5 29742 const unsigned char *ptrs = raw.data;
philpem@5 29743 for (unsigned int off = raw.width/4; off; --off) {
philpem@5 29744 *(ptr_r++) = (T)*(ptrs++);
philpem@5 29745 *(ptr_g++) = (T)*(ptrs++);
philpem@5 29746 *(ptr_b++) = (T)*(ptrs++);
philpem@5 29747 *(ptr_a++) = (T)*(ptrs++);
philpem@5 29748 }
philpem@5 29749 }
philpem@5 29750 if (!file) cimg::fclose(nfile);
philpem@5 29751 return *this;
philpem@5 29752 }
philpem@5 29753
philpem@5 29754 //! Load an image from a TIFF file.
philpem@5 29755 CImg<T>& load_tiff(const char *const filename,
philpem@5 29756 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 29757 const unsigned int step_frame=1) {
philpem@5 29758 if (!filename)
philpem@5 29759 throw CImgArgumentException("CImg<%s>::load_tiff() : Cannot load (null) filename.",
philpem@5 29760 pixel_type());
philpem@5 29761 const unsigned int
philpem@5 29762 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
philpem@5 29763 nstep_frame = step_frame?step_frame:1;
philpem@5 29764 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
philpem@5 29765
philpem@5 29766 #ifndef cimg_use_tiff
philpem@5 29767 if (nfirst_frame || nlast_frame!=~0U || nstep_frame>1)
philpem@5 29768 throw CImgArgumentException("CImg<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
philpem@5 29769 "('cimg_use_tiff' must be defined).",
philpem@5 29770 pixel_type(),filename);
philpem@5 29771 return load_other(filename);
philpem@5 29772 #else
philpem@5 29773 TIFF *tif = TIFFOpen(filename,"r");
philpem@5 29774 if (tif) {
philpem@5 29775 unsigned int nb_images = 0;
philpem@5 29776 do ++nb_images; while (TIFFReadDirectory(tif));
philpem@5 29777 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
philpem@5 29778 cimg::warn("CImg<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
philpem@5 29779 pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
philpem@5 29780 if (nfirst_frame>=nb_images) return assign();
philpem@5 29781 if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
philpem@5 29782 TIFFSetDirectory(tif,0);
philpem@5 29783 CImg<T> frame;
philpem@5 29784 for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) {
philpem@5 29785 frame._load_tiff(tif,l);
philpem@5 29786 if (l==nfirst_frame) assign(frame.width,frame.height,1+(nlast_frame-nfirst_frame)/nstep_frame,frame.dim);
philpem@5 29787 if (frame.width>width || frame.height>height || frame.dim>dim)
philpem@5 29788 resize(cimg::max(frame.width,width),cimg::max(frame.height,height),-100,cimg::max(frame.dim,dim),0);
philpem@5 29789 draw_image(0,0,(l-nfirst_frame)/nstep_frame,frame);
philpem@5 29790 }
philpem@5 29791 TIFFClose(tif);
philpem@5 29792 } else throw CImgException("CImg<%s>::load_tiff() : File '%s' cannot be opened.",
philpem@5 29793 pixel_type(),filename);
philpem@5 29794 return *this;
philpem@5 29795 #endif
philpem@5 29796 }
philpem@5 29797
philpem@5 29798 static CImg<T> get_load_tiff(const char *const filename,
philpem@5 29799 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 29800 const unsigned int step_frame=1) {
philpem@5 29801 return CImg<T>().load_tiff(filename,first_frame,last_frame,step_frame);
philpem@5 29802 }
philpem@5 29803
philpem@5 29804 // (Original contribution by Jerome Boulanger).
philpem@5 29805 #ifdef cimg_use_tiff
philpem@5 29806 CImg<T>& _load_tiff(TIFF *tif, const unsigned int directory) {
philpem@5 29807 if (!TIFFSetDirectory(tif,directory)) return assign();
philpem@5 29808 uint16 samplesperpixel, bitspersample;
philpem@5 29809 uint32 nx,ny;
philpem@5 29810 const char *const filename = TIFFFileName(tif);
philpem@5 29811 TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx);
philpem@5 29812 TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny);
philpem@5 29813 TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel);
philpem@5 29814 if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) {
philpem@5 29815 cimg::warn("CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.",
philpem@5 29816 pixel_type(),filename);
philpem@5 29817 samplesperpixel = 1;
philpem@5 29818 }
philpem@5 29819 TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample);
philpem@5 29820 assign(nx,ny,1,samplesperpixel);
philpem@5 29821 if (bitspersample!=8 || !(samplesperpixel==3 || samplesperpixel==4)) {
philpem@5 29822 uint16 photo, config;
philpem@5 29823 TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config);
philpem@5 29824 TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo);
philpem@5 29825 if (TIFFIsTiled(tif)) {
philpem@5 29826 uint32 tw, th;
philpem@5 29827 TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw);
philpem@5 29828 TIFFGetField(tif,TIFFTAG_TILELENGTH,&th);
philpem@5 29829 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
philpem@5 29830 case 8 : {
philpem@5 29831 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29832 if (buf) {
philpem@5 29833 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29834 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29835 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
philpem@5 29836 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29837 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29838 pixel_type(),filename);
philpem@5 29839 } else {
philpem@5 29840 unsigned char *ptr = buf;
philpem@5 29841 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29842 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29843 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29844 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
philpem@5 29845 }
philpem@5 29846 }
philpem@5 29847 _TIFFfree(buf);
philpem@5 29848 }
philpem@5 29849 } break;
philpem@5 29850 case 16 : {
philpem@5 29851 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29852 if (buf) {
philpem@5 29853 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29854 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29855 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
philpem@5 29856 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29857 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29858 pixel_type(),filename);
philpem@5 29859 } else {
philpem@5 29860 unsigned short *ptr = buf;
philpem@5 29861 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29862 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29863 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29864 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
philpem@5 29865 }
philpem@5 29866 }
philpem@5 29867 _TIFFfree(buf);
philpem@5 29868 }
philpem@5 29869 } break;
philpem@5 29870 case 32 : {
philpem@5 29871 float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29872 if (buf) {
philpem@5 29873 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29874 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29875 if (TIFFReadTile(tif,buf,col,row,0,0)<0) {
philpem@5 29876 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29877 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29878 pixel_type(),filename);
philpem@5 29879 } else {
philpem@5 29880 float *ptr = buf;
philpem@5 29881 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29882 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29883 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29884 (*this)(cc,rr,vv) = (T)(float)(ptr[(rr-row)*th*samplesperpixel + (cc-col)*samplesperpixel + vv]);
philpem@5 29885 }
philpem@5 29886 }
philpem@5 29887 _TIFFfree(buf);
philpem@5 29888 }
philpem@5 29889 } break;
philpem@5 29890 } else switch (bitspersample) {
philpem@5 29891 case 8 : {
philpem@5 29892 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29893 if (buf) {
philpem@5 29894 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29895 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29896 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29897 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
philpem@5 29898 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29899 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29900 pixel_type(),filename);
philpem@5 29901 } else {
philpem@5 29902 unsigned char *ptr = buf;
philpem@5 29903 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29904 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29905 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
philpem@5 29906 }
philpem@5 29907 }
philpem@5 29908 _TIFFfree(buf);
philpem@5 29909 }
philpem@5 29910 } break;
philpem@5 29911 case 16 : {
philpem@5 29912 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29913 if (buf) {
philpem@5 29914 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29915 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29916 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29917 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
philpem@5 29918 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29919 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29920 pixel_type(),filename);
philpem@5 29921 } else {
philpem@5 29922 unsigned short *ptr = buf;
philpem@5 29923 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29924 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29925 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
philpem@5 29926 }
philpem@5 29927 }
philpem@5 29928 _TIFFfree(buf);
philpem@5 29929 }
philpem@5 29930 } break;
philpem@5 29931 case 32 : {
philpem@5 29932 float *buf = (float*)_TIFFmalloc(TIFFTileSize(tif));
philpem@5 29933 if (buf) {
philpem@5 29934 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 29935 for (unsigned int row = 0; row<ny; row+=th)
philpem@5 29936 for (unsigned int col = 0; col<nx; col+=tw) {
philpem@5 29937 if (TIFFReadTile(tif,buf,col,row,0,vv)<0) {
philpem@5 29938 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29939 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a tile.",
philpem@5 29940 pixel_type(),filename);
philpem@5 29941 } else {
philpem@5 29942 float *ptr = buf;
philpem@5 29943 for (unsigned int rr = row; rr<cimg::min((unsigned int)(row+th),(unsigned int)ny); ++rr)
philpem@5 29944 for (unsigned int cc = col; cc<cimg::min((unsigned int)(col+tw),(unsigned int)nx); ++cc)
philpem@5 29945 (*this)(cc,rr,vv) = (T)(float)*(ptr++);
philpem@5 29946 }
philpem@5 29947 }
philpem@5 29948 _TIFFfree(buf);
philpem@5 29949 }
philpem@5 29950 } break;
philpem@5 29951 }
philpem@5 29952 } else {
philpem@5 29953 if (config==PLANARCONFIG_CONTIG) switch (bitspersample) {
philpem@5 29954 case 8 : {
philpem@5 29955 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 29956 if (buf) {
philpem@5 29957 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 29958 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 29959 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 29960 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 29961 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
philpem@5 29962 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 29963 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29964 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
philpem@5 29965 pixel_type(),filename);
philpem@5 29966 }
philpem@5 29967 unsigned char *ptr = buf;
philpem@5 29968 for (unsigned int rr = 0; rr<nrow; ++rr)
philpem@5 29969 for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 29970 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 29971 }
philpem@5 29972 _TIFFfree(buf);
philpem@5 29973 }
philpem@5 29974 } break;
philpem@5 29975 case 16 : {
philpem@5 29976 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 29977 if (buf) {
philpem@5 29978 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 29979 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 29980 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 29981 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 29982 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
philpem@5 29983 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 29984 _TIFFfree(buf); TIFFClose(tif);
philpem@5 29985 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
philpem@5 29986 pixel_type(),filename);
philpem@5 29987 }
philpem@5 29988 unsigned short *ptr = buf;
philpem@5 29989 for (unsigned int rr = 0; rr<nrow; ++rr)
philpem@5 29990 for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 29991 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 29992 }
philpem@5 29993 _TIFFfree(buf);
philpem@5 29994 }
philpem@5 29995 } break;
philpem@5 29996 case 32 : {
philpem@5 29997 float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 29998 if (buf) {
philpem@5 29999 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 30000 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 30001 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 30002 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 30003 tstrip_t strip = TIFFComputeStrip(tif, row, 0);
philpem@5 30004 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 30005 _TIFFfree(buf); TIFFClose(tif);
philpem@5 30006 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
philpem@5 30007 pixel_type(),filename);
philpem@5 30008 }
philpem@5 30009 float *ptr = buf;
philpem@5 30010 for (unsigned int rr = 0; rr<nrow; ++rr)
philpem@5 30011 for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 30012 for (unsigned int vv = 0; vv<samplesperpixel; ++vv) (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 30013 }
philpem@5 30014 _TIFFfree(buf);
philpem@5 30015 }
philpem@5 30016 } break;
philpem@5 30017 } else switch (bitspersample){
philpem@5 30018 case 8 : {
philpem@5 30019 unsigned char *buf = (unsigned char*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 30020 if (buf) {
philpem@5 30021 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 30022 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 30023 for (unsigned int vv=0; vv<samplesperpixel; ++vv)
philpem@5 30024 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 30025 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 30026 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
philpem@5 30027 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 30028 _TIFFfree(buf); TIFFClose(tif);
philpem@5 30029 throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.",
philpem@5 30030 pixel_type(),filename);
philpem@5 30031 }
philpem@5 30032 unsigned char *ptr = buf;
philpem@5 30033 for (unsigned int rr = 0;rr<nrow; ++rr)
philpem@5 30034 for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 30035 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 30036 }
philpem@5 30037 _TIFFfree(buf);
philpem@5 30038 }
philpem@5 30039 } break;
philpem@5 30040 case 16 : {
philpem@5 30041 unsigned short *buf = (unsigned short*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 30042 if (buf) {
philpem@5 30043 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 30044 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 30045 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 30046 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 30047 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 30048 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
philpem@5 30049 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 30050 _TIFFfree(buf); TIFFClose(tif);
philpem@5 30051 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
philpem@5 30052 pixel_type(),filename);
philpem@5 30053 }
philpem@5 30054 unsigned short *ptr = buf;
philpem@5 30055 for (unsigned int rr = 0; rr<nrow; ++rr)
philpem@5 30056 for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 30057 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 30058 }
philpem@5 30059 _TIFFfree(buf);
philpem@5 30060 }
philpem@5 30061 } break;
philpem@5 30062 case 32 : {
philpem@5 30063 float *buf = (float*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 30064 if (buf) {
philpem@5 30065 uint32 row, rowsperstrip = (uint32)-1;
philpem@5 30066 TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip);
philpem@5 30067 for (unsigned int vv = 0; vv<samplesperpixel; ++vv)
philpem@5 30068 for (row = 0; row<ny; row+= rowsperstrip) {
philpem@5 30069 uint32 nrow = (row+rowsperstrip>ny?ny-row:rowsperstrip);
philpem@5 30070 tstrip_t strip = TIFFComputeStrip(tif, row, vv);
philpem@5 30071 if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) {
philpem@5 30072 _TIFFfree(buf); TIFFClose(tif);
philpem@5 30073 throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.",
philpem@5 30074 pixel_type(),filename);
philpem@5 30075 }
philpem@5 30076 float *ptr = buf;
philpem@5 30077 for (unsigned int rr = 0; rr<nrow; ++rr) for (unsigned int cc = 0; cc<nx; ++cc)
philpem@5 30078 (*this)(cc,row+rr,vv) = (T)(float)*(ptr++);
philpem@5 30079 }
philpem@5 30080 _TIFFfree(buf);
philpem@5 30081 }
philpem@5 30082 } break;
philpem@5 30083 }
philpem@5 30084 }
philpem@5 30085 } else {
philpem@5 30086 uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32));
philpem@5 30087 if (!raster) {
philpem@5 30088 _TIFFfree(raster); TIFFClose(tif);
philpem@5 30089 throw CImgException("CImg<%s>::load_tiff() : File '%s', not enough memory for buffer allocation.",
philpem@5 30090 pixel_type(),filename);
philpem@5 30091 }
philpem@5 30092 TIFFReadRGBAImage(tif,nx,ny,raster,0);
philpem@5 30093 switch (samplesperpixel) {
philpem@5 30094 case 1 : {
philpem@5 30095 cimg_forXY(*this,x,y) (*this)(x,y) = (T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257);
philpem@5 30096 } break;
philpem@5 30097 case 3 : {
philpem@5 30098 cimg_forXY(*this,x,y) {
philpem@5 30099 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
philpem@5 30100 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
philpem@5 30101 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
philpem@5 30102 }
philpem@5 30103 } break;
philpem@5 30104 case 4 : {
philpem@5 30105 cimg_forXY(*this,x,y) {
philpem@5 30106 (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]);
philpem@5 30107 (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]);
philpem@5 30108 (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]);
philpem@5 30109 (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]);
philpem@5 30110 }
philpem@5 30111 } break;
philpem@5 30112 }
philpem@5 30113 _TIFFfree(raster);
philpem@5 30114 }
philpem@5 30115 return *this;
philpem@5 30116 }
philpem@5 30117 #endif
philpem@5 30118
philpem@5 30119 //! Load an image from an ANALYZE7.5/NIFTI file.
philpem@5 30120 CImg<T>& load_analyze(const char *const filename, float *const voxsize=0) {
philpem@5 30121 return _load_analyze(0,filename,voxsize);
philpem@5 30122 }
philpem@5 30123
philpem@5 30124 static CImg<T> get_load_analyze(const char *const filename, float *const voxsize=0) {
philpem@5 30125 return CImg<T>().load_analyze(filename,voxsize);
philpem@5 30126 }
philpem@5 30127
philpem@5 30128 //! Load an image from an ANALYZE7.5/NIFTI file.
philpem@5 30129 CImg<T>& load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
philpem@5 30130 return _load_analyze(file,0,voxsize);
philpem@5 30131 }
philpem@5 30132
philpem@5 30133 static CImg<T> get_load_analyze(cimg_std::FILE *const file, float *const voxsize=0) {
philpem@5 30134 return CImg<T>().load_analyze(file,voxsize);
philpem@5 30135 }
philpem@5 30136
philpem@5 30137 CImg<T>& _load_analyze(cimg_std::FILE *const file, const char *const filename, float *const voxsize=0) {
philpem@5 30138 if (!filename && !file)
philpem@5 30139 throw CImgArgumentException("CImg<%s>::load_analyze() : Cannot load (null) filename.",
philpem@5 30140 pixel_type());
philpem@5 30141 cimg_std::FILE *nfile_header = 0, *nfile = 0;
philpem@5 30142 if (!file) {
philpem@5 30143 char body[1024];
philpem@5 30144 const char *ext = cimg::split_filename(filename,body);
philpem@5 30145 if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file.
philpem@5 30146 nfile_header = cimg::fopen(filename,"rb");
philpem@5 30147 cimg_std::sprintf(body+cimg::strlen(body),".img");
philpem@5 30148 nfile = cimg::fopen(body,"rb");
philpem@5 30149 } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file.
philpem@5 30150 nfile = cimg::fopen(filename,"rb");
philpem@5 30151 cimg_std::sprintf(body+cimg::strlen(body),".hdr");
philpem@5 30152 nfile_header = cimg::fopen(body,"rb");
philpem@5 30153 } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file.
philpem@5 30154 } else nfile_header = nfile = file; // File is a Niftii file.
philpem@5 30155 if (!nfile || !nfile_header)
philpem@5 30156 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', not recognized as an Analyze7.5 or NIFTI file.",
philpem@5 30157 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30158
philpem@5 30159 // Read header.
philpem@5 30160 bool endian = false;
philpem@5 30161 unsigned int header_size;
philpem@5 30162 cimg::fread(&header_size,1,nfile_header);
philpem@5 30163 if (!header_size)
philpem@5 30164 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', zero-sized header found.",
philpem@5 30165 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30166 if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); }
philpem@5 30167 unsigned char *header = new unsigned char[header_size];
philpem@5 30168 cimg::fread(header+4,header_size-4,nfile_header);
philpem@5 30169 if (!file && nfile_header!=nfile) cimg::fclose(nfile_header);
philpem@5 30170 if (endian) {
philpem@5 30171 cimg::invert_endianness((short*)(header+40),5);
philpem@5 30172 cimg::invert_endianness((short*)(header+70),1);
philpem@5 30173 cimg::invert_endianness((short*)(header+72),1);
philpem@5 30174 cimg::invert_endianness((float*)(header+76),4);
philpem@5 30175 cimg::invert_endianness((float*)(header+112),1);
philpem@5 30176 }
philpem@5 30177 unsigned short *dim = (unsigned short*)(header+40), dimx = 1, dimy = 1, dimz = 1, dimv = 1;
philpem@5 30178 if (!dim[0])
philpem@5 30179 cimg::warn("CImg<%s>::load_analyze() : File '%s', tells that image has zero dimensions.",
philpem@5 30180 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30181 if (dim[0]>4)
philpem@5 30182 cimg::warn("CImg<%s>::load_analyze() : File '%s', number of image dimension is %u, reading only the 4 first dimensions",
philpem@5 30183 pixel_type(),filename?filename:"(FILE*)",dim[0]);
philpem@5 30184 if (dim[0]>=1) dimx = dim[1];
philpem@5 30185 if (dim[0]>=2) dimy = dim[2];
philpem@5 30186 if (dim[0]>=3) dimz = dim[3];
philpem@5 30187 if (dim[0]>=4) dimv = dim[4];
philpem@5 30188 float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1;
philpem@5 30189 const unsigned short datatype = *(short*)(header+70);
philpem@5 30190 if (voxsize) {
philpem@5 30191 const float *vsize = (float*)(header+76);
philpem@5 30192 voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3];
philpem@5 30193 }
philpem@5 30194 delete[] header;
philpem@5 30195
philpem@5 30196 // Read pixel data.
philpem@5 30197 assign(dimx,dimy,dimz,dimv);
philpem@5 30198 switch (datatype) {
philpem@5 30199 case 2 : {
philpem@5 30200 unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv];
philpem@5 30201 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
philpem@5 30202 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
philpem@5 30203 delete[] buffer;
philpem@5 30204 } break;
philpem@5 30205 case 4 : {
philpem@5 30206 short *buffer = new short[dimx*dimy*dimz*dimv];
philpem@5 30207 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
philpem@5 30208 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
philpem@5 30209 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
philpem@5 30210 delete[] buffer;
philpem@5 30211 } break;
philpem@5 30212 case 8 : {
philpem@5 30213 int *buffer = new int[dimx*dimy*dimz*dimv];
philpem@5 30214 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
philpem@5 30215 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
philpem@5 30216 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
philpem@5 30217 delete[] buffer;
philpem@5 30218 } break;
philpem@5 30219 case 16 : {
philpem@5 30220 float *buffer = new float[dimx*dimy*dimz*dimv];
philpem@5 30221 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
philpem@5 30222 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
philpem@5 30223 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
philpem@5 30224 delete[] buffer;
philpem@5 30225 } break;
philpem@5 30226 case 64 : {
philpem@5 30227 double *buffer = new double[dimx*dimy*dimz*dimv];
philpem@5 30228 cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile);
philpem@5 30229 if (endian) cimg::invert_endianness(buffer,dimx*dimy*dimz*dimv);
philpem@5 30230 cimg_foroff(*this,off) data[off] = (T)(buffer[off]*scalefactor);
philpem@5 30231 delete[] buffer;
philpem@5 30232 } break;
philpem@5 30233 default :
philpem@5 30234 if (!file) cimg::fclose(nfile);
philpem@5 30235 throw CImgIOException("CImg<%s>::load_analyze() : File '%s', cannot read images with 'datatype = %d'",
philpem@5 30236 pixel_type(),filename?filename:"(FILE*)",datatype);
philpem@5 30237 }
philpem@5 30238 if (!file) cimg::fclose(nfile);
philpem@5 30239 return *this;
philpem@5 30240 }
philpem@5 30241
philpem@5 30242 //! Load an image (list) from a .cimg file.
philpem@5 30243 CImg<T>& load_cimg(const char *const filename, const char axis='z', const char align='p') {
philpem@5 30244 CImgList<T> list;
philpem@5 30245 list.load_cimg(filename);
philpem@5 30246 if (list.size==1) return list[0].transfer_to(*this);
philpem@5 30247 return assign(list.get_append(axis,align));
philpem@5 30248 }
philpem@5 30249
philpem@5 30250 static CImg<T> get_load_cimg(const char *const filename, const char axis='z', const char align='p') {
philpem@5 30251 return CImg<T>().load_cimg(filename,axis,align);
philpem@5 30252 }
philpem@5 30253
philpem@5 30254 //! Load an image (list) from a .cimg file.
philpem@5 30255 CImg<T>& load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
philpem@5 30256 CImgList<T> list;
philpem@5 30257 list.load_cimg(file);
philpem@5 30258 if (list.size==1) return list[0].transfer_to(*this);
philpem@5 30259 return assign(list.get_append(axis,align));
philpem@5 30260 }
philpem@5 30261
philpem@5 30262 static CImg<T> get_load_cimg(cimg_std::FILE *const file, const char axis='z', const char align='p') {
philpem@5 30263 return CImg<T>().load_cimg(file,axis,align);
philpem@5 30264 }
philpem@5 30265
philpem@5 30266 //! Load a sub-image (list) from a .cimg file.
philpem@5 30267 CImg<T>& load_cimg(const char *const filename,
philpem@5 30268 const unsigned int n0, const unsigned int n1,
philpem@5 30269 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 30270 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
philpem@5 30271 const char axis='z', const char align='p') {
philpem@5 30272 CImgList<T> list;
philpem@5 30273 list.load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 30274 if (list.size==1) return list[0].transfer_to(*this);
philpem@5 30275 return assign(list.get_append(axis,align));
philpem@5 30276 }
philpem@5 30277
philpem@5 30278 static CImg<T> get_load_cimg(const char *const filename,
philpem@5 30279 const unsigned int n0, const unsigned int n1,
philpem@5 30280 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 30281 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
philpem@5 30282 const char axis='z', const char align='p') {
philpem@5 30283 return CImg<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
philpem@5 30284 }
philpem@5 30285
philpem@5 30286 //! Load a sub-image (list) from a non-compressed .cimg file.
philpem@5 30287 CImg<T>& load_cimg(cimg_std::FILE *const file,
philpem@5 30288 const unsigned int n0, const unsigned int n1,
philpem@5 30289 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 30290 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
philpem@5 30291 const char axis='z', const char align='p') {
philpem@5 30292 CImgList<T> list;
philpem@5 30293 list.load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 30294 if (list.size==1) return list[0].transfer_to(*this);
philpem@5 30295 return assign(list.get_append(axis,align));
philpem@5 30296 }
philpem@5 30297
philpem@5 30298 static CImg<T> get_load_cimg(cimg_std::FILE *const file,
philpem@5 30299 const unsigned int n0, const unsigned int n1,
philpem@5 30300 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 30301 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1,
philpem@5 30302 const char axis='z', const char align='p') {
philpem@5 30303 return CImg<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1,axis,align);
philpem@5 30304 }
philpem@5 30305
philpem@5 30306 //! Load an image from an INRIMAGE-4 file.
philpem@5 30307 CImg<T>& load_inr(const char *const filename, float *const voxsize=0) {
philpem@5 30308 return _load_inr(0,filename,voxsize);
philpem@5 30309 }
philpem@5 30310
philpem@5 30311 static CImg<T> get_load_inr(const char *const filename, float *const voxsize=0) {
philpem@5 30312 return CImg<T>().load_inr(filename,voxsize);
philpem@5 30313 }
philpem@5 30314
philpem@5 30315 //! Load an image from an INRIMAGE-4 file.
philpem@5 30316 CImg<T>& load_inr(cimg_std::FILE *const file, float *const voxsize=0) {
philpem@5 30317 return _load_inr(file,0,voxsize);
philpem@5 30318 }
philpem@5 30319
philpem@5 30320 static CImg<T> get_load_inr(cimg_std::FILE *const file, float *voxsize=0) {
philpem@5 30321 return CImg<T>().load_inr(file,voxsize);
philpem@5 30322 }
philpem@5 30323
philpem@5 30324 // Load an image from an INRIMAGE-4 file (internal).
philpem@5 30325 static void _load_inr_header(cimg_std::FILE *file, int out[8], float *const voxsize) {
philpem@5 30326 char item[1024], tmp1[64], tmp2[64];
philpem@5 30327 out[0] = cimg_std::fscanf(file,"%63s",item);
philpem@5 30328 out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1;
philpem@5 30329 if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0)
philpem@5 30330 throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n"
philpem@5 30331 "(INRIMAGE-4 identifier not found)",
philpem@5 30332 pixel_type());
philpem@5 30333 while (cimg_std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) {
philpem@5 30334 cimg_std::sscanf(item," XDIM%*[^0-9]%d",out);
philpem@5 30335 cimg_std::sscanf(item," YDIM%*[^0-9]%d",out+1);
philpem@5 30336 cimg_std::sscanf(item," ZDIM%*[^0-9]%d",out+2);
philpem@5 30337 cimg_std::sscanf(item," VDIM%*[^0-9]%d",out+3);
philpem@5 30338 cimg_std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6);
philpem@5 30339 if (voxsize) {
philpem@5 30340 cimg_std::sscanf(item," VX%*[^0-9.+-]%f",voxsize);
philpem@5 30341 cimg_std::sscanf(item," VY%*[^0-9.+-]%f",voxsize+1);
philpem@5 30342 cimg_std::sscanf(item," VZ%*[^0-9.+-]%f",voxsize+2);
philpem@5 30343 }
philpem@5 30344 if (cimg_std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1;
philpem@5 30345 switch (cimg_std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) {
philpem@5 30346 case 0 : break;
philpem@5 30347 case 2 : out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; cimg_std::strcpy(tmp1,tmp2);
philpem@5 30348 case 1 :
philpem@5 30349 if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0;
philpem@5 30350 if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1;
philpem@5 30351 if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2;
philpem@5 30352 if (out[4]>=0) break;
philpem@5 30353 default :
philpem@5 30354 throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2);
philpem@5 30355 }
philpem@5 30356 }
philpem@5 30357 if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0)
philpem@5 30358 throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )",
philpem@5 30359 pixel_type(),out[0],out[1],out[2],out[3]);
philpem@5 30360 if(out[4]<0 || out[5]<0)
philpem@5 30361 throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",
philpem@5 30362 pixel_type());
philpem@5 30363 if(out[6]<0)
philpem@5 30364 throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",
philpem@5 30365 pixel_type());
philpem@5 30366 if(out[7]<0)
philpem@5 30367 throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",
philpem@5 30368 pixel_type());
philpem@5 30369 }
philpem@5 30370
philpem@5 30371 CImg<T>& _load_inr(cimg_std::FILE *const file, const char *const filename, float *const voxsize) {
philpem@5 30372 #define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \
philpem@5 30373 if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \
philpem@5 30374 Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \
philpem@5 30375 cimg_forYZ(*this,y,z) { \
philpem@5 30376 cimg::fread(val,fopt[0]*fopt[3],nfile); \
philpem@5 30377 if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \
philpem@5 30378 xval = val; cimg_forX(*this,x) cimg_forV(*this,k) (*this)(x,y,z,k) = (T)*(xval++); \
philpem@5 30379 } \
philpem@5 30380 delete[] val; \
philpem@5 30381 loaded = true; \
philpem@5 30382 }
philpem@5 30383
philpem@5 30384 if (!filename && !file)
philpem@5 30385 throw CImgArgumentException("CImg<%s>::load_inr() : Cannot load (null) filename.",
philpem@5 30386 pixel_type());
philpem@5 30387 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 30388 int fopt[8], endian=cimg::endianness()?1:0;
philpem@5 30389 bool loaded = false;
philpem@5 30390 if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1;
philpem@5 30391 _load_inr_header(nfile,fopt,voxsize);
philpem@5 30392 assign(fopt[0],fopt[1],fopt[2],fopt[3]);
philpem@5 30393 _cimg_load_inr_case(0,0,8, unsigned char);
philpem@5 30394 _cimg_load_inr_case(0,1,8, char);
philpem@5 30395 _cimg_load_inr_case(0,0,16,unsigned short);
philpem@5 30396 _cimg_load_inr_case(0,1,16,short);
philpem@5 30397 _cimg_load_inr_case(0,0,32,unsigned int);
philpem@5 30398 _cimg_load_inr_case(0,1,32,int);
philpem@5 30399 _cimg_load_inr_case(1,0,32,float);
philpem@5 30400 _cimg_load_inr_case(1,1,32,float);
philpem@5 30401 _cimg_load_inr_case(1,0,64,double);
philpem@5 30402 _cimg_load_inr_case(1,1,64,double);
philpem@5 30403 if (!loaded) {
philpem@5 30404 if (!file) cimg::fclose(nfile);
philpem@5 30405 throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file",
philpem@5 30406 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30407 }
philpem@5 30408 if (!file) cimg::fclose(nfile);
philpem@5 30409 return *this;
philpem@5 30410 }
philpem@5 30411
philpem@5 30412 //! Load an image from a PANDORE file.
philpem@5 30413 CImg<T>& load_pandore(const char *const filename) {
philpem@5 30414 return _load_pandore(0,filename);
philpem@5 30415 }
philpem@5 30416
philpem@5 30417 static CImg<T> get_load_pandore(const char *const filename) {
philpem@5 30418 return CImg<T>().load_pandore(filename);
philpem@5 30419 }
philpem@5 30420
philpem@5 30421 //! Load an image from a PANDORE file.
philpem@5 30422 CImg<T>& load_pandore(cimg_std::FILE *const file) {
philpem@5 30423 return _load_pandore(file,0);
philpem@5 30424 }
philpem@5 30425
philpem@5 30426 static CImg<T> get_load_pandore(cimg_std::FILE *const file) {
philpem@5 30427 return CImg<T>().load_pandore(file);
philpem@5 30428 }
philpem@5 30429
philpem@5 30430 CImg<T>& _load_pandore(cimg_std::FILE *const file, const char *const filename) {
philpem@5 30431 #define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \
philpem@5 30432 cimg::fread(dims,nbdim,nfile); \
philpem@5 30433 if (endian) cimg::invert_endianness(dims,nbdim); \
philpem@5 30434 assign(nwidth,nheight,ndepth,ndim); \
philpem@5 30435 const unsigned int siz = size(); \
philpem@5 30436 stype *buffer = new stype[siz]; \
philpem@5 30437 cimg::fread(buffer,siz,nfile); \
philpem@5 30438 if (endian) cimg::invert_endianness(buffer,siz); \
philpem@5 30439 T *ptrd = data; \
philpem@5 30440 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \
philpem@5 30441 buffer-=siz; \
philpem@5 30442 delete[] buffer
philpem@5 30443
philpem@5 30444 #define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \
philpem@5 30445 if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \
philpem@5 30446 else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \
philpem@5 30447 else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \
philpem@5 30448 else throw CImgIOException("CImg<%s>::load_pandore() : File '%s' cannot be read, datatype not supported on this architecture.", \
philpem@5 30449 pixel_type(),filename?filename:"(FILE*)"); }
philpem@5 30450
philpem@5 30451 if (!filename && !file)
philpem@5 30452 throw CImgArgumentException("CImg<%s>::load_pandore() : Cannot load (null) filename.",
philpem@5 30453 pixel_type());
philpem@5 30454 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 30455 typedef unsigned char uchar;
philpem@5 30456 typedef unsigned short ushort;
philpem@5 30457 typedef unsigned int uint;
philpem@5 30458 typedef unsigned long ulong;
philpem@5 30459 char header[32];
philpem@5 30460 cimg::fread(header,12,nfile);
philpem@5 30461 if (cimg::strncasecmp("PANDORE",header,7)) {
philpem@5 30462 if (!file) cimg::fclose(nfile);
philpem@5 30463 throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file, "
philpem@5 30464 "(PANDORE identifier not found).",
philpem@5 30465 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30466 }
philpem@5 30467 unsigned int imageid, dims[8];
philpem@5 30468 cimg::fread(&imageid,1,nfile);
philpem@5 30469 const bool endian = (imageid>255);
philpem@5 30470 if (endian) cimg::invert_endianness(imageid);
philpem@5 30471 cimg::fread(header,20,nfile);
philpem@5 30472
philpem@5 30473 switch (imageid) {
philpem@5 30474 case 2: _cimg_load_pandore_case(2,dims[1],1,1,1,uchar,uchar,uchar,1); break;
philpem@5 30475 case 3: _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break;
philpem@5 30476 case 4: _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break;
philpem@5 30477 case 5: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,uchar,uchar,uchar,1); break;
philpem@5 30478 case 6: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break;
philpem@5 30479 case 7: _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break;
philpem@5 30480 case 8: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,uchar,uchar,uchar,1); break;
philpem@5 30481 case 9: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break;
philpem@5 30482 case 10: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break;
philpem@5 30483 case 11 : { // Region 1D
philpem@5 30484 cimg::fread(dims,3,nfile);
philpem@5 30485 if (endian) cimg::invert_endianness(dims,3);
philpem@5 30486 assign(dims[1],1,1,1);
philpem@5 30487 const unsigned siz = size();
philpem@5 30488 if (dims[2]<256) {
philpem@5 30489 unsigned char *buffer = new unsigned char[siz];
philpem@5 30490 cimg::fread(buffer,siz,nfile);
philpem@5 30491 T *ptrd = data;
philpem@5 30492 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30493 buffer-=siz;
philpem@5 30494 delete[] buffer;
philpem@5 30495 } else {
philpem@5 30496 if (dims[2]<65536) {
philpem@5 30497 unsigned short *buffer = new unsigned short[siz];
philpem@5 30498 cimg::fread(buffer,siz,nfile);
philpem@5 30499 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30500 T *ptrd = data;
philpem@5 30501 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30502 buffer-=siz;
philpem@5 30503 delete[] buffer;
philpem@5 30504 } else {
philpem@5 30505 unsigned int *buffer = new unsigned int[siz];
philpem@5 30506 cimg::fread(buffer,siz,nfile);
philpem@5 30507 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30508 T *ptrd = data;
philpem@5 30509 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30510 buffer-=siz;
philpem@5 30511 delete[] buffer;
philpem@5 30512 }
philpem@5 30513 }
philpem@5 30514 }
philpem@5 30515 break;
philpem@5 30516 case 12 : { // Region 2D
philpem@5 30517 cimg::fread(dims,4,nfile);
philpem@5 30518 if (endian) cimg::invert_endianness(dims,4);
philpem@5 30519 assign(dims[2],dims[1],1,1);
philpem@5 30520 const unsigned int siz = size();
philpem@5 30521 if (dims[3]<256) {
philpem@5 30522 unsigned char *buffer = new unsigned char[siz];
philpem@5 30523 cimg::fread(buffer,siz,nfile);
philpem@5 30524 T *ptrd = data;
philpem@5 30525 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30526 buffer-=siz;
philpem@5 30527 delete[] buffer;
philpem@5 30528 } else {
philpem@5 30529 if (dims[3]<65536) {
philpem@5 30530 unsigned short *buffer = new unsigned short[siz];
philpem@5 30531 cimg::fread(buffer,siz,nfile);
philpem@5 30532 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30533 T *ptrd = data;
philpem@5 30534 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30535 buffer-=siz;
philpem@5 30536 delete[] buffer;
philpem@5 30537 } else {
philpem@5 30538 unsigned long *buffer = new unsigned long[siz];
philpem@5 30539 cimg::fread(buffer,siz,nfile);
philpem@5 30540 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30541 T *ptrd = data;
philpem@5 30542 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30543 buffer-=siz;
philpem@5 30544 delete[] buffer;
philpem@5 30545 }
philpem@5 30546 }
philpem@5 30547 }
philpem@5 30548 break;
philpem@5 30549 case 13 : { // Region 3D
philpem@5 30550 cimg::fread(dims,5,nfile);
philpem@5 30551 if (endian) cimg::invert_endianness(dims,5);
philpem@5 30552 assign(dims[3],dims[2],dims[1],1);
philpem@5 30553 const unsigned int siz = size();
philpem@5 30554 if (dims[4]<256) {
philpem@5 30555 unsigned char *buffer = new unsigned char[siz];
philpem@5 30556 cimg::fread(buffer,siz,nfile);
philpem@5 30557 T *ptrd = data;
philpem@5 30558 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30559 buffer-=siz;
philpem@5 30560 delete[] buffer;
philpem@5 30561 } else {
philpem@5 30562 if (dims[4]<65536) {
philpem@5 30563 unsigned short *buffer = new unsigned short[siz];
philpem@5 30564 cimg::fread(buffer,siz,nfile);
philpem@5 30565 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30566 T *ptrd = data;
philpem@5 30567 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30568 buffer-=siz;
philpem@5 30569 delete[] buffer;
philpem@5 30570 } else {
philpem@5 30571 unsigned int *buffer = new unsigned int[siz];
philpem@5 30572 cimg::fread(buffer,siz,nfile);
philpem@5 30573 if (endian) cimg::invert_endianness(buffer,siz);
philpem@5 30574 T *ptrd = data;
philpem@5 30575 cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++);
philpem@5 30576 buffer-=siz;
philpem@5 30577 delete[] buffer;
philpem@5 30578 }
philpem@5 30579 }
philpem@5 30580 }
philpem@5 30581 break;
philpem@5 30582 case 16: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,uchar,uchar,uchar,1); break;
philpem@5 30583 case 17: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break;
philpem@5 30584 case 18: _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break;
philpem@5 30585 case 19: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,uchar,uchar,uchar,1); break;
philpem@5 30586 case 20: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break;
philpem@5 30587 case 21: _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break;
philpem@5 30588 case 22: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],uchar,uchar,uchar,1); break;
philpem@5 30589 case 23: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4);
philpem@5 30590 case 24: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],ulong,uint,ushort,4); break;
philpem@5 30591 case 25: _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break;
philpem@5 30592 case 26: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],uchar,uchar,uchar,1); break;
philpem@5 30593 case 27: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break;
philpem@5 30594 case 28: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],ulong,uint,ushort,4); break;
philpem@5 30595 case 29: _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break;
philpem@5 30596 case 30: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],uchar,uchar,uchar,1); break;
philpem@5 30597 case 31: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break;
philpem@5 30598 case 32: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],ulong,uint,ushort,4); break;
philpem@5 30599 case 33: _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break;
philpem@5 30600 case 34 : { // Points 1D
philpem@5 30601 int ptbuf[4];
philpem@5 30602 cimg::fread(ptbuf,1,nfile);
philpem@5 30603 if (endian) cimg::invert_endianness(ptbuf,1);
philpem@5 30604 assign(1); (*this)(0) = (T)ptbuf[0];
philpem@5 30605 } break;
philpem@5 30606 case 35 : { // Points 2D
philpem@5 30607 int ptbuf[4];
philpem@5 30608 cimg::fread(ptbuf,2,nfile);
philpem@5 30609 if (endian) cimg::invert_endianness(ptbuf,2);
philpem@5 30610 assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0];
philpem@5 30611 } break;
philpem@5 30612 case 36 : { // Points 3D
philpem@5 30613 int ptbuf[4];
philpem@5 30614 cimg::fread(ptbuf,3,nfile);
philpem@5 30615 if (endian) cimg::invert_endianness(ptbuf,3);
philpem@5 30616 assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0];
philpem@5 30617 } break;
philpem@5 30618 default :
philpem@5 30619 if (!file) cimg::fclose(nfile);
philpem@5 30620 throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type = %u",
philpem@5 30621 pixel_type(),filename?filename:"(FILE*)",imageid);
philpem@5 30622 }
philpem@5 30623 if (!file) cimg::fclose(nfile);
philpem@5 30624 return *this;
philpem@5 30625 }
philpem@5 30626
philpem@5 30627 //! Load an image from a PAR-REC (Philips) file.
philpem@5 30628 CImg<T>& load_parrec(const char *const filename, const char axis='v', const char align='p') {
philpem@5 30629 CImgList<T> list;
philpem@5 30630 list.load_parrec(filename);
philpem@5 30631 if (list.size==1) return list[0].transfer_to(*this);
philpem@5 30632 return assign(list.get_append(axis,align));
philpem@5 30633 }
philpem@5 30634
philpem@5 30635 static CImg<T> get_load_parrec(const char *const filename, const char axis='v', const char align='p') {
philpem@5 30636 return CImg<T>().load_parrec(filename,axis,align);
philpem@5 30637 }
philpem@5 30638
philpem@5 30639 //! Load an image from a .RAW file.
philpem@5 30640 CImg<T>& load_raw(const char *const filename,
philpem@5 30641 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30642 const unsigned int sizez=1, const unsigned int sizev=1,
philpem@5 30643 const bool multiplexed=false, const bool invert_endianness=false) {
philpem@5 30644 return _load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
philpem@5 30645 }
philpem@5 30646
philpem@5 30647 static CImg<T> get_load_raw(const char *const filename,
philpem@5 30648 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30649 const unsigned int sizez=1, const unsigned int sizev=1,
philpem@5 30650 const bool multiplexed=false, const bool invert_endianness=false) {
philpem@5 30651 return CImg<T>().load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
philpem@5 30652 }
philpem@5 30653
philpem@5 30654 //! Load an image from a .RAW file.
philpem@5 30655 CImg<T>& load_raw(cimg_std::FILE *const file,
philpem@5 30656 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30657 const unsigned int sizez=1, const unsigned int sizev=1,
philpem@5 30658 const bool multiplexed=false, const bool invert_endianness=false) {
philpem@5 30659 return _load_raw(file,0,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
philpem@5 30660 }
philpem@5 30661
philpem@5 30662 static CImg<T> get_load_raw(cimg_std::FILE *const file,
philpem@5 30663 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30664 const unsigned int sizez=1, const unsigned int sizev=1,
philpem@5 30665 const bool multiplexed=false, const bool invert_endianness=false) {
philpem@5 30666 return CImg<T>().load_raw(file,sizex,sizey,sizez,sizev,multiplexed,invert_endianness);
philpem@5 30667 }
philpem@5 30668
philpem@5 30669 CImg<T>& _load_raw(cimg_std::FILE *const file, const char *const filename,
philpem@5 30670 const unsigned int sizex, const unsigned int sizey,
philpem@5 30671 const unsigned int sizez, const unsigned int sizev,
philpem@5 30672 const bool multiplexed, const bool invert_endianness) {
philpem@5 30673 if (!filename && !file)
philpem@5 30674 throw CImgArgumentException("CImg<%s>::load_raw() : Cannot load (null) filename.",
philpem@5 30675 pixel_type());
philpem@5 30676 assign(sizex,sizey,sizez,sizev,0);
philpem@5 30677 const unsigned int siz = size();
philpem@5 30678 if (siz) {
philpem@5 30679 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 30680 if (!multiplexed) {
philpem@5 30681 cimg::fread(data,siz,nfile);
philpem@5 30682 if (invert_endianness) cimg::invert_endianness(data,siz);
philpem@5 30683 }
philpem@5 30684 else {
philpem@5 30685 CImg<T> buf(1,1,1,sizev);
philpem@5 30686 cimg_forXYZ(*this,x,y,z) {
philpem@5 30687 cimg::fread(buf.data,sizev,nfile);
philpem@5 30688 if (invert_endianness) cimg::invert_endianness(buf.data,sizev);
philpem@5 30689 set_vector_at(buf,x,y,z); }
philpem@5 30690 }
philpem@5 30691 if (!file) cimg::fclose(nfile);
philpem@5 30692 }
philpem@5 30693 return *this;
philpem@5 30694 }
philpem@5 30695
philpem@5 30696 //! Load a video sequence using FFMPEG av's libraries.
philpem@5 30697 CImg<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30698 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
philpem@5 30699 const char axis='z', const char align='p') {
philpem@5 30700 return get_load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume,axis,align).transfer_to(*this);
philpem@5 30701 }
philpem@5 30702
philpem@5 30703 static CImg<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30704 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false,
philpem@5 30705 const char axis='z', const char align='p') {
philpem@5 30706 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format,resume).get_append(axis,align);
philpem@5 30707 }
philpem@5 30708
philpem@5 30709 //! Load an image sequence from a YUV file.
philpem@5 30710 CImg<T>& load_yuv(const char *const filename,
philpem@5 30711 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30712 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30713 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
philpem@5 30714 return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
philpem@5 30715 }
philpem@5 30716
philpem@5 30717 static CImg<T> get_load_yuv(const char *const filename,
philpem@5 30718 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30719 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30720 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
philpem@5 30721 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
philpem@5 30722 }
philpem@5 30723
philpem@5 30724 //! Load an image sequence from a YUV file.
philpem@5 30725 CImg<T>& load_yuv(cimg_std::FILE *const file,
philpem@5 30726 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30727 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30728 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
philpem@5 30729 return get_load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb,axis,align).transfer_to(*this);
philpem@5 30730 }
philpem@5 30731
philpem@5 30732 static CImg<T> get_load_yuv(cimg_std::FILE *const file,
philpem@5 30733 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 30734 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 30735 const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z', const char align='p') {
philpem@5 30736 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb).get_append(axis,align);
philpem@5 30737 }
philpem@5 30738
philpem@5 30739 //! Load a 3D object from a .OFF file.
philpem@5 30740 template<typename tf, typename tc>
philpem@5 30741 CImg<T>& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
philpem@5 30742 return _load_off(0,filename,primitives,colors,invert_faces);
philpem@5 30743 }
philpem@5 30744
philpem@5 30745 template<typename tf, typename tc>
philpem@5 30746 static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors,
philpem@5 30747 const bool invert_faces=false) {
philpem@5 30748 return CImg<T>().load_off(filename,primitives,colors,invert_faces);
philpem@5 30749 }
philpem@5 30750
philpem@5 30751 //! Load a 3D object from a .OFF file.
philpem@5 30752 template<typename tf, typename tc>
philpem@5 30753 CImg<T>& load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces=false) {
philpem@5 30754 return _load_off(file,0,primitives,colors,invert_faces);
philpem@5 30755 }
philpem@5 30756
philpem@5 30757 template<typename tf, typename tc>
philpem@5 30758 static CImg<T> get_load_off(cimg_std::FILE *const file, CImgList<tf>& primitives, CImgList<tc>& colors,
philpem@5 30759 const bool invert_faces=false) {
philpem@5 30760 return CImg<T>().load_off(file,primitives,colors,invert_faces);
philpem@5 30761 }
philpem@5 30762
philpem@5 30763 template<typename tf, typename tc>
philpem@5 30764 CImg<T>& _load_off(cimg_std::FILE *const file, const char *const filename,
philpem@5 30765 CImgList<tf>& primitives, CImgList<tc>& colors, const bool invert_faces) {
philpem@5 30766 if (!filename && !file)
philpem@5 30767 throw CImgArgumentException("CImg<%s>::load_off() : Cannot load (null) filename.",
philpem@5 30768 pixel_type());
philpem@5 30769 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"r");
philpem@5 30770 unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0;
philpem@5 30771 char line[256] = { 0 };
philpem@5 30772 int err;
philpem@5 30773
philpem@5 30774 // Skip comments, and read magic string OFF
philpem@5 30775 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
philpem@5 30776 if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) {
philpem@5 30777 if (!file) cimg::fclose(nfile);
philpem@5 30778 throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",
philpem@5 30779 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30780 }
philpem@5 30781 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
philpem@5 30782 if ((err = cimg_std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) {
philpem@5 30783 if (!file) cimg::fclose(nfile);
philpem@5 30784 throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",
philpem@5 30785 pixel_type(),filename?filename:"(FILE*)");
philpem@5 30786 }
philpem@5 30787
philpem@5 30788 // Read points data
philpem@5 30789 assign(nb_points,3);
philpem@5 30790 float X = 0, Y = 0, Z = 0;
philpem@5 30791 cimg_forX(*this,l) {
philpem@5 30792 do { err = cimg_std::fscanf(nfile,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#'));
philpem@5 30793 if ((err = cimg_std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) {
philpem@5 30794 if (!file) cimg::fclose(nfile);
philpem@5 30795 throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",
philpem@5 30796 pixel_type(),filename?filename:"(FILE*)",l+1,nb_points);
philpem@5 30797 }
philpem@5 30798 (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
philpem@5 30799 }
philpem@5 30800
philpem@5 30801 // Read primitive data
philpem@5 30802 primitives.assign();
philpem@5 30803 colors.assign();
philpem@5 30804 bool stopflag = false;
philpem@5 30805 while (!stopflag) {
philpem@5 30806 float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
philpem@5 30807 unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
philpem@5 30808 line[0]='\0';
philpem@5 30809 if ((err = cimg_std::fscanf(nfile,"%u",&prim))!=1) stopflag=true;
philpem@5 30810 else {
philpem@5 30811 ++nb_read;
philpem@5 30812 switch (prim) {
philpem@5 30813 case 1 : {
philpem@5 30814 if ((err = cimg_std::fscanf(nfile,"%u%255[^\n] ",&i0,line))<2) {
philpem@5 30815 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30816 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30817 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30818 } else {
philpem@5 30819 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30820 primitives.insert(CImg<tf>::vector(i0));
philpem@5 30821 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
philpem@5 30822 }
philpem@5 30823 } break;
philpem@5 30824 case 2 : {
philpem@5 30825 if ((err = cimg_std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line))<2) {
philpem@5 30826 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30827 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30828 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30829 } else {
philpem@5 30830 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30831 primitives.insert(CImg<tf>::vector(i0,i1));
philpem@5 30832 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
philpem@5 30833 }
philpem@5 30834 } break;
philpem@5 30835 case 3 : {
philpem@5 30836 if ((err = cimg_std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) {
philpem@5 30837 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30838 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30839 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30840 } else {
philpem@5 30841 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30842 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2));
philpem@5 30843 else primitives.insert(CImg<tf>::vector(i0,i2,i1));
philpem@5 30844 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)));
philpem@5 30845 }
philpem@5 30846 } break;
philpem@5 30847 case 4 : {
philpem@5 30848 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) {
philpem@5 30849 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30850 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30851 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30852 } else {
philpem@5 30853 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30854 if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
philpem@5 30855 else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
philpem@5 30856 colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
philpem@5 30857 }
philpem@5 30858 } break;
philpem@5 30859 case 5 : {
philpem@5 30860 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) {
philpem@5 30861 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30862 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30863 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30864 } else {
philpem@5 30865 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30866 if (invert_faces) {
philpem@5 30867 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
philpem@5 30868 primitives.insert(CImg<tf>::vector(i0,i3,i4));
philpem@5 30869 }
philpem@5 30870 else {
philpem@5 30871 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
philpem@5 30872 primitives.insert(CImg<tf>::vector(i0,i4,i3));
philpem@5 30873 }
philpem@5 30874 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
philpem@5 30875 ++nb_primitives;
philpem@5 30876 }
philpem@5 30877 } break;
philpem@5 30878 case 6 : {
philpem@5 30879 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) {
philpem@5 30880 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30881 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30882 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30883 } else {
philpem@5 30884 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30885 if (invert_faces) {
philpem@5 30886 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
philpem@5 30887 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
philpem@5 30888 }
philpem@5 30889 else {
philpem@5 30890 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
philpem@5 30891 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
philpem@5 30892 }
philpem@5 30893 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
philpem@5 30894 ++nb_primitives;
philpem@5 30895 }
philpem@5 30896 } break;
philpem@5 30897 case 7 : {
philpem@5 30898 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) {
philpem@5 30899 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30900 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30901 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30902 } else {
philpem@5 30903 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30904 if (invert_faces) {
philpem@5 30905 primitives.insert(CImg<tf>::vector(i0,i1,i3,i4));
philpem@5 30906 primitives.insert(CImg<tf>::vector(i0,i4,i5,i6));
philpem@5 30907 primitives.insert(CImg<tf>::vector(i1,i2,i3));
philpem@5 30908 }
philpem@5 30909 else {
philpem@5 30910 primitives.insert(CImg<tf>::vector(i0,i4,i3,i1));
philpem@5 30911 primitives.insert(CImg<tf>::vector(i0,i6,i5,i4));
philpem@5 30912 primitives.insert(CImg<tf>::vector(i3,i2,i1));
philpem@5 30913 }
philpem@5 30914 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
philpem@5 30915 ++(++nb_primitives);
philpem@5 30916 }
philpem@5 30917 } break;
philpem@5 30918 case 8 : {
philpem@5 30919 if ((err = cimg_std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) {
philpem@5 30920 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.",
philpem@5 30921 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives);
philpem@5 30922 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30923 } else {
philpem@5 30924 err = cimg_std::sscanf(line,"%f%f%f",&c0,&c1,&c2);
philpem@5 30925 if (invert_faces) {
philpem@5 30926 primitives.insert(CImg<tf>::vector(i0,i1,i2,i3));
philpem@5 30927 primitives.insert(CImg<tf>::vector(i0,i3,i4,i5));
philpem@5 30928 primitives.insert(CImg<tf>::vector(i0,i5,i6,i7));
philpem@5 30929 }
philpem@5 30930 else {
philpem@5 30931 primitives.insert(CImg<tf>::vector(i0,i3,i2,i1));
philpem@5 30932 primitives.insert(CImg<tf>::vector(i0,i5,i4,i3));
philpem@5 30933 primitives.insert(CImg<tf>::vector(i0,i7,i6,i5));
philpem@5 30934 }
philpem@5 30935 colors.insert(2,CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255)));
philpem@5 30936 ++(++nb_primitives);
philpem@5 30937 }
philpem@5 30938 } break;
philpem@5 30939 default :
philpem@5 30940 cimg::warn("CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).",
philpem@5 30941 pixel_type(),filename?filename:"(FILE*)",nb_read,nb_primitives,prim);
philpem@5 30942 err = cimg_std::fscanf(nfile,"%*[^\n] ");
philpem@5 30943 }
philpem@5 30944 }
philpem@5 30945 }
philpem@5 30946 if (!file) cimg::fclose(nfile);
philpem@5 30947 if (primitives.size!=nb_primitives)
philpem@5 30948 cimg::warn("CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.",
philpem@5 30949 pixel_type(),filename?filename:"(FILE*)",primitives.size,nb_primitives);
philpem@5 30950 return *this;
philpem@5 30951 }
philpem@5 30952
philpem@5 30953 //! Load a video sequence using FFMPEG's external tool 'ffmpeg'.
philpem@5 30954 CImg<T>& load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
philpem@5 30955 return get_load_ffmpeg_external(filename,axis,align).transfer_to(*this);
philpem@5 30956 }
philpem@5 30957
philpem@5 30958 static CImg<T> get_load_ffmpeg_external(const char *const filename, const char axis='z', const char align='p') {
philpem@5 30959 return CImgList<T>().load_ffmpeg_external(filename).get_append(axis,align);
philpem@5 30960 }
philpem@5 30961
philpem@5 30962 //! Load an image using GraphicsMagick's external tool 'gm'.
philpem@5 30963 CImg<T>& load_graphicsmagick_external(const char *const filename) {
philpem@5 30964 if (!filename)
philpem@5 30965 throw CImgArgumentException("CImg<%s>::load_graphicsmagick_external() : Cannot load (null) filename.",
philpem@5 30966 pixel_type());
philpem@5 30967 char command[1024], filetmp[512];
philpem@5 30968 cimg_std::FILE *file = 0;
philpem@5 30969 #if cimg_OS==1
philpem@5 30970 cimg_std::sprintf(command,"%s convert \"%s\" ppm:-",cimg::graphicsmagick_path(),filename);
philpem@5 30971 file = popen(command,"r");
philpem@5 30972 if (file) { load_pnm(file); pclose(file); return *this; }
philpem@5 30973 #endif
philpem@5 30974 do {
philpem@5 30975 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 30976 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 30977 } while (file);
philpem@5 30978 cimg_std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp);
philpem@5 30979 cimg::system(command,cimg::graphicsmagick_path());
philpem@5 30980 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
philpem@5 30981 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 30982 throw CImgIOException("CImg<%s>::load_graphicsmagick_external() : Failed to open image '%s'.\n\n"
philpem@5 30983 "Path of 'GraphicsMagick's gm' : \"%s\"\n"
philpem@5 30984 "Path of temporary filename : \"%s\"",
philpem@5 30985 pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
philpem@5 30986 } else cimg::fclose(file);
philpem@5 30987 load_pnm(filetmp);
philpem@5 30988 cimg_std::remove(filetmp);
philpem@5 30989 return *this;
philpem@5 30990 }
philpem@5 30991
philpem@5 30992 static CImg<T> get_load_graphicsmagick_external(const char *const filename) {
philpem@5 30993 return CImg<T>().load_graphicsmagick_external(filename);
philpem@5 30994 }
philpem@5 30995
philpem@5 30996 //! Load a gzipped image file, using external tool 'gunzip'.
philpem@5 30997 CImg<T>& load_gzip_external(const char *const filename) {
philpem@5 30998 if (!filename)
philpem@5 30999 throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
philpem@5 31000 pixel_type());
philpem@5 31001 char command[1024], filetmp[512], body[512];
philpem@5 31002 const char
philpem@5 31003 *ext = cimg::split_filename(filename,body),
philpem@5 31004 *ext2 = cimg::split_filename(body,0);
philpem@5 31005 cimg_std::FILE *file = 0;
philpem@5 31006 do {
philpem@5 31007 if (!cimg::strcasecmp(ext,"gz")) {
philpem@5 31008 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 31009 cimg::filenamerand(),ext2);
philpem@5 31010 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 31011 cimg::filenamerand());
philpem@5 31012 } else {
philpem@5 31013 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 31014 cimg::filenamerand(),ext);
philpem@5 31015 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 31016 cimg::filenamerand());
philpem@5 31017 }
philpem@5 31018 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 31019 } while (file);
philpem@5 31020 cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
philpem@5 31021 cimg::system(command);
philpem@5 31022 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
philpem@5 31023 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 31024 throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
philpem@5 31025 pixel_type(),filename);
philpem@5 31026 } else cimg::fclose(file);
philpem@5 31027 load(filetmp);
philpem@5 31028 cimg_std::remove(filetmp);
philpem@5 31029 return *this;
philpem@5 31030 }
philpem@5 31031
philpem@5 31032 static CImg<T> get_load_gzip_external(const char *const filename) {
philpem@5 31033 return CImg<T>().load_gzip_external(filename);
philpem@5 31034 }
philpem@5 31035
philpem@5 31036 //! Load an image using ImageMagick's external tool 'convert'.
philpem@5 31037 CImg<T>& load_imagemagick_external(const char *const filename) {
philpem@5 31038 if (!filename)
philpem@5 31039 throw CImgArgumentException("CImg<%s>::load_imagemagick_external() : Cannot load (null) filename.",
philpem@5 31040 pixel_type());
philpem@5 31041 char command[1024], filetmp[512];
philpem@5 31042 cimg_std::FILE *file = 0;
philpem@5 31043 #if cimg_OS==1
philpem@5 31044 cimg_std::sprintf(command,"%s \"%s\" ppm:-",cimg::imagemagick_path(),filename);
philpem@5 31045 file = popen(command,"r");
philpem@5 31046 if (file) { load_pnm(file); pclose(file); return *this; }
philpem@5 31047 #endif
philpem@5 31048 do {
philpem@5 31049 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 31050 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 31051 } while (file);
philpem@5 31052 cimg_std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp);
philpem@5 31053 cimg::system(command,cimg::imagemagick_path());
philpem@5 31054 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
philpem@5 31055 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 31056 throw CImgIOException("CImg<%s>::load_imagemagick_external() : Failed to open image '%s'.\n\n"
philpem@5 31057 "Path of 'ImageMagick's convert' : \"%s\"\n"
philpem@5 31058 "Path of temporary filename : \"%s\"",
philpem@5 31059 pixel_type(),filename,cimg::imagemagick_path(),filetmp);
philpem@5 31060 } else cimg::fclose(file);
philpem@5 31061 load_pnm(filetmp);
philpem@5 31062 cimg_std::remove(filetmp);
philpem@5 31063 return *this;
philpem@5 31064 }
philpem@5 31065
philpem@5 31066 static CImg<T> get_load_imagemagick_external(const char *const filename) {
philpem@5 31067 return CImg<T>().load_imagemagick_external(filename);
philpem@5 31068 }
philpem@5 31069
philpem@5 31070 //! Load a DICOM image file, using XMedcon's external tool 'medcon'.
philpem@5 31071 CImg<T>& load_medcon_external(const char *const filename) {
philpem@5 31072 if (!filename)
philpem@5 31073 throw CImgArgumentException("CImg<%s>::load_medcon_external() : Cannot load (null) filename.",
philpem@5 31074 pixel_type());
philpem@5 31075 char command[1024], filetmp[512], body[512];
philpem@5 31076 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 31077 cimg_std::FILE *file = 0;
philpem@5 31078 do {
philpem@5 31079 cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
philpem@5 31080 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 31081 } while (file);
philpem@5 31082 cimg_std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename);
philpem@5 31083 cimg::system(command);
philpem@5 31084 cimg::split_filename(filetmp,body);
philpem@5 31085 cimg_std::sprintf(command,"m000-%s.hdr",body);
philpem@5 31086 file = cimg_std::fopen(command,"rb");
philpem@5 31087 if (!file) {
philpem@5 31088 throw CImgIOException("CImg<%s>::load_medcon_external() : Failed to open image '%s'.\n\n"
philpem@5 31089 "Path of 'medcon' : \"%s\"\n"
philpem@5 31090 "Path of temporary filename : \"%s\"",
philpem@5 31091 pixel_type(),filename,cimg::medcon_path(),filetmp);
philpem@5 31092 } else cimg::fclose(file);
philpem@5 31093 load_analyze(command);
philpem@5 31094 cimg_std::remove(command);
philpem@5 31095 cimg_std::sprintf(command,"m000-%s.img",body);
philpem@5 31096 cimg_std::remove(command);
philpem@5 31097 return *this;
philpem@5 31098 }
philpem@5 31099
philpem@5 31100 static CImg<T> get_load_medcon_external(const char *const filename) {
philpem@5 31101 return CImg<T>().load_medcon_external(filename);
philpem@5 31102 }
philpem@5 31103
philpem@5 31104 //! Load a RAW Color Camera image file, using external tool 'dcraw'.
philpem@5 31105 CImg<T>& load_dcraw_external(const char *const filename) {
philpem@5 31106 if (!filename)
philpem@5 31107 throw CImgArgumentException("CImg<%s>::load_dcraw_external() : Cannot load (null) filename.",
philpem@5 31108 pixel_type());
philpem@5 31109 char command[1024], filetmp[512];
philpem@5 31110 cimg_std::FILE *file = 0;
philpem@5 31111 #if cimg_OS==1
philpem@5 31112 cimg_std::sprintf(command,"%s -4 -c \"%s\"",cimg::dcraw_path(),filename);
philpem@5 31113 file = popen(command,"r");
philpem@5 31114 if (file) { load_pnm(file); pclose(file); return *this; }
philpem@5 31115 #endif
philpem@5 31116 do {
philpem@5 31117 cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 31118 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 31119 } while (file);
philpem@5 31120 cimg_std::sprintf(command,"%s -4 -c \"%s\" > %s",cimg::dcraw_path(),filename,filetmp);
philpem@5 31121 cimg::system(command,cimg::dcraw_path());
philpem@5 31122 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
philpem@5 31123 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 31124 throw CImgIOException("CImg<%s>::load_dcraw_external() : Failed to open image '%s'.\n\n"
philpem@5 31125 "Path of 'dcraw' : \"%s\"\n"
philpem@5 31126 "Path of temporary filename : \"%s\"",
philpem@5 31127 pixel_type(),filename,cimg::dcraw_path(),filetmp);
philpem@5 31128 } else cimg::fclose(file);
philpem@5 31129 load_pnm(filetmp);
philpem@5 31130 cimg_std::remove(filetmp);
philpem@5 31131 return *this;
philpem@5 31132 }
philpem@5 31133
philpem@5 31134 static CImg<T> get_load_dcraw_external(const char *const filename) {
philpem@5 31135 return CImg<T>().load_dcraw_external(filename);
philpem@5 31136 }
philpem@5 31137
philpem@5 31138 //! Load an image using ImageMagick's or GraphicsMagick's executables.
philpem@5 31139 CImg<T>& load_other(const char *const filename) {
philpem@5 31140 if (!filename)
philpem@5 31141 throw CImgArgumentException("CImg<%s>::load_other() : Cannot load (null) filename.",
philpem@5 31142 pixel_type());
philpem@5 31143 const unsigned int odebug = cimg::exception_mode();
philpem@5 31144 cimg::exception_mode() = 0;
philpem@5 31145 try { load_magick(filename); }
philpem@5 31146 catch (CImgException&) {
philpem@5 31147 try { load_imagemagick_external(filename); }
philpem@5 31148 catch (CImgException&) {
philpem@5 31149 try { load_graphicsmagick_external(filename); }
philpem@5 31150 catch (CImgException&) {
philpem@5 31151 assign();
philpem@5 31152 }
philpem@5 31153 }
philpem@5 31154 }
philpem@5 31155 cimg::exception_mode() = odebug;
philpem@5 31156 if (is_empty())
philpem@5 31157 throw CImgIOException("CImg<%s>::load_other() : File '%s' cannot be opened.",
philpem@5 31158 pixel_type(),filename);
philpem@5 31159 return *this;
philpem@5 31160 }
philpem@5 31161
philpem@5 31162 static CImg<T> get_load_other(const char *const filename) {
philpem@5 31163 return CImg<T>().load_other(filename);
philpem@5 31164 }
philpem@5 31165
philpem@5 31166 //@}
philpem@5 31167 //---------------------------
philpem@5 31168 //
philpem@5 31169 //! \name Image File Saving
philpem@5 31170 //@{
philpem@5 31171 //---------------------------
philpem@5 31172
philpem@5 31173 //! Save the image as a file.
philpem@5 31174 /**
philpem@5 31175 The used file format is defined by the file extension in the filename \p filename.
philpem@5 31176 Parameter \p number can be used to add a 6-digit number to the filename before saving.
philpem@5 31177 **/
philpem@5 31178 const CImg<T>& save(const char *const filename, const int number=-1) const {
philpem@5 31179 if (is_empty())
philpem@5 31180 throw CImgInstanceException("CImg<%s>::save() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31181 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 31182 if (!filename)
philpem@5 31183 throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) cannot be saved as a (null) filename.",
philpem@5 31184 pixel_type(),width,height,depth,dim,data);
philpem@5 31185 const char *ext = cimg::split_filename(filename);
philpem@5 31186 char nfilename[1024];
philpem@5 31187 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
philpem@5 31188 #ifdef cimg_save_plugin
philpem@5 31189 cimg_save_plugin(fn);
philpem@5 31190 #endif
philpem@5 31191 #ifdef cimg_save_plugin1
philpem@5 31192 cimg_save_plugin1(fn);
philpem@5 31193 #endif
philpem@5 31194 #ifdef cimg_save_plugin2
philpem@5 31195 cimg_save_plugin2(fn);
philpem@5 31196 #endif
philpem@5 31197 #ifdef cimg_save_plugin3
philpem@5 31198 cimg_save_plugin3(fn);
philpem@5 31199 #endif
philpem@5 31200 #ifdef cimg_save_plugin4
philpem@5 31201 cimg_save_plugin4(fn);
philpem@5 31202 #endif
philpem@5 31203 #ifdef cimg_save_plugin5
philpem@5 31204 cimg_save_plugin5(fn);
philpem@5 31205 #endif
philpem@5 31206 #ifdef cimg_save_plugin6
philpem@5 31207 cimg_save_plugin6(fn);
philpem@5 31208 #endif
philpem@5 31209 #ifdef cimg_save_plugin7
philpem@5 31210 cimg_save_plugin7(fn);
philpem@5 31211 #endif
philpem@5 31212 #ifdef cimg_save_plugin8
philpem@5 31213 cimg_save_plugin8(fn);
philpem@5 31214 #endif
philpem@5 31215 // ASCII formats
philpem@5 31216 if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn);
philpem@5 31217 if (!cimg::strcasecmp(ext,"dlm") ||
philpem@5 31218 !cimg::strcasecmp(ext,"txt")) return save_dlm(fn);
philpem@5 31219 if (!cimg::strcasecmp(ext,"cpp") ||
philpem@5 31220 !cimg::strcasecmp(ext,"hpp") ||
philpem@5 31221 !cimg::strcasecmp(ext,"h") ||
philpem@5 31222 !cimg::strcasecmp(ext,"c")) return save_cpp(fn);
philpem@5 31223
philpem@5 31224 // 2D binary formats
philpem@5 31225 if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn);
philpem@5 31226 if (!cimg::strcasecmp(ext,"jpg") ||
philpem@5 31227 !cimg::strcasecmp(ext,"jpeg") ||
philpem@5 31228 !cimg::strcasecmp(ext,"jpe") ||
philpem@5 31229 !cimg::strcasecmp(ext,"jfif") ||
philpem@5 31230 !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn);
philpem@5 31231 if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn);
philpem@5 31232 if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn);
philpem@5 31233 if (!cimg::strcasecmp(ext,"png")) return save_png(fn);
philpem@5 31234 if (!cimg::strcasecmp(ext,"pgm") ||
philpem@5 31235 !cimg::strcasecmp(ext,"ppm") ||
philpem@5 31236 !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn);
philpem@5 31237 if (!cimg::strcasecmp(ext,"tif") ||
philpem@5 31238 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
philpem@5 31239
philpem@5 31240 // 3D binary formats
philpem@5 31241 if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
philpem@5 31242 if (!cimg::strcasecmp(ext,"cimg") || ext[0]=='\0') return save_cimg(fn,false);
philpem@5 31243 if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn);
philpem@5 31244 if (!cimg::strcasecmp(ext,"hdr") ||
philpem@5 31245 !cimg::strcasecmp(ext,"nii")) return save_analyze(fn);
philpem@5 31246 if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn);
philpem@5 31247 if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn);
philpem@5 31248 if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn);
philpem@5 31249
philpem@5 31250 // Archive files
philpem@5 31251 if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
philpem@5 31252
philpem@5 31253 // Image sequences
philpem@5 31254 if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
philpem@5 31255 if (!cimg::strcasecmp(ext,"avi") ||
philpem@5 31256 !cimg::strcasecmp(ext,"mov") ||
philpem@5 31257 !cimg::strcasecmp(ext,"asf") ||
philpem@5 31258 !cimg::strcasecmp(ext,"divx") ||
philpem@5 31259 !cimg::strcasecmp(ext,"flv") ||
philpem@5 31260 !cimg::strcasecmp(ext,"mpg") ||
philpem@5 31261 !cimg::strcasecmp(ext,"m1v") ||
philpem@5 31262 !cimg::strcasecmp(ext,"m2v") ||
philpem@5 31263 !cimg::strcasecmp(ext,"m4v") ||
philpem@5 31264 !cimg::strcasecmp(ext,"mjp") ||
philpem@5 31265 !cimg::strcasecmp(ext,"mkv") ||
philpem@5 31266 !cimg::strcasecmp(ext,"mpe") ||
philpem@5 31267 !cimg::strcasecmp(ext,"movie") ||
philpem@5 31268 !cimg::strcasecmp(ext,"ogm") ||
philpem@5 31269 !cimg::strcasecmp(ext,"qt") ||
philpem@5 31270 !cimg::strcasecmp(ext,"rm") ||
philpem@5 31271 !cimg::strcasecmp(ext,"vob") ||
philpem@5 31272 !cimg::strcasecmp(ext,"wmv") ||
philpem@5 31273 !cimg::strcasecmp(ext,"xvid") ||
philpem@5 31274 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
philpem@5 31275 return save_other(fn);
philpem@5 31276 }
philpem@5 31277
philpem@5 31278 // Save the image as an ASCII file (ASCII Raw + simple header) (internal).
philpem@5 31279 const CImg<T>& _save_ascii(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31280 if (is_empty())
philpem@5 31281 throw CImgInstanceException("CImg<%s>::save_ascii() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31282 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31283 if (!file && !filename)
philpem@5 31284 throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31285 pixel_type(),width,height,depth,dim,data);
philpem@5 31286 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
philpem@5 31287 cimg_std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim);
philpem@5 31288 const T* ptrs = data;
philpem@5 31289 cimg_forYZV(*this,y,z,v) {
philpem@5 31290 cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g ",(double)*(ptrs++));
philpem@5 31291 cimg_std::fputc('\n',nfile);
philpem@5 31292 }
philpem@5 31293 if (!file) cimg::fclose(nfile);
philpem@5 31294 return *this;
philpem@5 31295 }
philpem@5 31296
philpem@5 31297 //! Save the image as an ASCII file (ASCII Raw + simple header).
philpem@5 31298 const CImg<T>& save_ascii(const char *const filename) const {
philpem@5 31299 return _save_ascii(0,filename);
philpem@5 31300 }
philpem@5 31301
philpem@5 31302 //! Save the image as an ASCII file (ASCII Raw + simple header).
philpem@5 31303 const CImg<T>& save_ascii(cimg_std::FILE *const file) const {
philpem@5 31304 return _save_ascii(file,0);
philpem@5 31305 }
philpem@5 31306
philpem@5 31307 // Save the image as a C or CPP source file (internal).
philpem@5 31308 const CImg<T>& _save_cpp(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31309 if (!file && !filename)
philpem@5 31310 throw CImgArgumentException("CImg<%s>::save_cpp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31311 pixel_type(),width,height,depth,dim,data);
philpem@5 31312 if (is_empty())
philpem@5 31313 throw CImgInstanceException("CImg<%s>::save_cpp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31314 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31315 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
philpem@5 31316 char varname[1024] = { 0 };
philpem@5 31317 if (filename) cimg_std::sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname);
philpem@5 31318 if (varname[0]=='\0') cimg_std::sprintf(varname,"unnamed");
philpem@5 31319 cimg_std::fprintf(nfile,
philpem@5 31320 "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n"
philpem@5 31321 "%s data_%s[] = { \n ",
philpem@5 31322 varname,width,height,depth,dim,pixel_type(),pixel_type(),varname);
philpem@5 31323 for (unsigned long off = 0, siz = size()-1; off<=siz; ++off) {
philpem@5 31324 cimg_std::fprintf(nfile,cimg::type<T>::format(),cimg::type<T>::format((*this)[off]));
philpem@5 31325 if (off==siz) cimg_std::fprintf(nfile," };\n");
philpem@5 31326 else if (!((off+1)%16)) cimg_std::fprintf(nfile,",\n ");
philpem@5 31327 else cimg_std::fprintf(nfile,", ");
philpem@5 31328 }
philpem@5 31329 if (!file) cimg::fclose(nfile);
philpem@5 31330 return *this;
philpem@5 31331 }
philpem@5 31332
philpem@5 31333 //! Save the image as a CPP source file.
philpem@5 31334 const CImg<T>& save_cpp(const char *const filename) const {
philpem@5 31335 return _save_cpp(0,filename);
philpem@5 31336 }
philpem@5 31337
philpem@5 31338 //! Save the image as a CPP source file.
philpem@5 31339 const CImg<T>& save_cpp(cimg_std::FILE *const file) const {
philpem@5 31340 return _save_cpp(file,0);
philpem@5 31341 }
philpem@5 31342
philpem@5 31343 // Save the image as a DLM file (internal).
philpem@5 31344 const CImg<T>& _save_dlm(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31345 if (is_empty())
philpem@5 31346 throw CImgInstanceException("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31347 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31348 if (!file && !filename)
philpem@5 31349 throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31350 pixel_type(),width,height,depth,dim,data);
philpem@5 31351 if (depth>1)
philpem@5 31352 cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled.",
philpem@5 31353 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31354 if (dim>1)
philpem@5 31355 cimg::warn("CImg<%s>::save_dlm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. "
philpem@5 31356 "Pixel values along V will be unrolled.",
philpem@5 31357 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31358
philpem@5 31359 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
philpem@5 31360 const T* ptrs = data;
philpem@5 31361 cimg_forYZV(*this,y,z,v) {
philpem@5 31362 cimg_forX(*this,x) cimg_std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==dimx()-1)?"":",");
philpem@5 31363 cimg_std::fputc('\n',nfile);
philpem@5 31364 }
philpem@5 31365 if (!file) cimg::fclose(nfile);
philpem@5 31366 return *this;
philpem@5 31367 }
philpem@5 31368
philpem@5 31369 //! Save the image as a DLM file.
philpem@5 31370 const CImg<T>& save_dlm(const char *const filename) const {
philpem@5 31371 return _save_dlm(0,filename);
philpem@5 31372 }
philpem@5 31373
philpem@5 31374 //! Save the image as a DLM file.
philpem@5 31375 const CImg<T>& save_dlm(cimg_std::FILE *const file) const {
philpem@5 31376 return _save_dlm(file,0);
philpem@5 31377 }
philpem@5 31378
philpem@5 31379 // Save the image as a BMP file (internal).
philpem@5 31380 const CImg<T>& _save_bmp(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31381 if (is_empty())
philpem@5 31382 throw CImgInstanceException("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31383 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31384 if (!file && !filename)
philpem@5 31385 throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31386 pixel_type(),width,height,depth,dim,data);
philpem@5 31387 if (depth>1)
philpem@5 31388 cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
philpem@5 31389 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31390 if (dim>3)
philpem@5 31391 cimg::warn("CImg<%s>::save_bmp() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
philpem@5 31392 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31393
philpem@5 31394 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 31395 unsigned char header[54] = { 0 }, align_buf[4] = { 0 };
philpem@5 31396 const unsigned int
philpem@5 31397 align = (4 - (3*width)%4)%4,
philpem@5 31398 buf_size = (3*width+align)*dimy(),
philpem@5 31399 file_size = 54 + buf_size;
philpem@5 31400 header[0] = 'B'; header[1] = 'M';
philpem@5 31401 header[0x02] = file_size&0xFF;
philpem@5 31402 header[0x03] = (file_size>>8)&0xFF;
philpem@5 31403 header[0x04] = (file_size>>16)&0xFF;
philpem@5 31404 header[0x05] = (file_size>>24)&0xFF;
philpem@5 31405 header[0x0A] = 0x36;
philpem@5 31406 header[0x0E] = 0x28;
philpem@5 31407 header[0x12] = width&0xFF;
philpem@5 31408 header[0x13] = (width>>8)&0xFF;
philpem@5 31409 header[0x14] = (width>>16)&0xFF;
philpem@5 31410 header[0x15] = (width>>24)&0xFF;
philpem@5 31411 header[0x16] = height&0xFF;
philpem@5 31412 header[0x17] = (height>>8)&0xFF;
philpem@5 31413 header[0x18] = (height>>16)&0xFF;
philpem@5 31414 header[0x19] = (height>>24)&0xFF;
philpem@5 31415 header[0x1A] = 1;
philpem@5 31416 header[0x1B] = 0;
philpem@5 31417 header[0x1C] = 24;
philpem@5 31418 header[0x1D] = 0;
philpem@5 31419 header[0x22] = buf_size&0xFF;
philpem@5 31420 header[0x23] = (buf_size>>8)&0xFF;
philpem@5 31421 header[0x24] = (buf_size>>16)&0xFF;
philpem@5 31422 header[0x25] = (buf_size>>24)&0xFF;
philpem@5 31423 header[0x27] = 0x1;
philpem@5 31424 header[0x2B] = 0x1;
philpem@5 31425 cimg::fwrite(header,54,nfile);
philpem@5 31426
philpem@5 31427 const T
philpem@5 31428 *pR = ptr(0,height-1,0,0),
philpem@5 31429 *pG = (dim>=2)?ptr(0,height-1,0,1):0,
philpem@5 31430 *pB = (dim>=3)?ptr(0,height-1,0,2):0;
philpem@5 31431
philpem@5 31432 switch (dim) {
philpem@5 31433 case 1 : {
philpem@5 31434 cimg_forY(*this,y) { cimg_forX(*this,x) {
philpem@5 31435 const unsigned char val = (unsigned char)*(pR++);
philpem@5 31436 cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile); cimg_std::fputc(val,nfile);
philpem@5 31437 }
philpem@5 31438 cimg::fwrite(align_buf,align,nfile);
philpem@5 31439 pR-=2*width;
philpem@5 31440 }} break;
philpem@5 31441 case 2 : {
philpem@5 31442 cimg_forY(*this,y) { cimg_forX(*this,x) {
philpem@5 31443 cimg_std::fputc(0,nfile);
philpem@5 31444 cimg_std::fputc((unsigned char)(*(pG++)),nfile);
philpem@5 31445 cimg_std::fputc((unsigned char)(*(pR++)),nfile);
philpem@5 31446 }
philpem@5 31447 cimg::fwrite(align_buf,align,nfile);
philpem@5 31448 pR-=2*width; pG-=2*width;
philpem@5 31449 }} break;
philpem@5 31450 default : {
philpem@5 31451 cimg_forY(*this,y) { cimg_forX(*this,x) {
philpem@5 31452 cimg_std::fputc((unsigned char)(*(pB++)),nfile);
philpem@5 31453 cimg_std::fputc((unsigned char)(*(pG++)),nfile);
philpem@5 31454 cimg_std::fputc((unsigned char)(*(pR++)),nfile);
philpem@5 31455 }
philpem@5 31456 cimg::fwrite(align_buf,align,nfile);
philpem@5 31457 pR-=2*width; pG-=2*width; pB-=2*width;
philpem@5 31458 }
philpem@5 31459 }
philpem@5 31460 }
philpem@5 31461 if (!file) cimg::fclose(nfile);
philpem@5 31462 return *this;
philpem@5 31463 }
philpem@5 31464
philpem@5 31465 //! Save the image as a BMP file.
philpem@5 31466 const CImg<T>& save_bmp(const char *const filename) const {
philpem@5 31467 return _save_bmp(0,filename);
philpem@5 31468 }
philpem@5 31469
philpem@5 31470 //! Save the image as a BMP file.
philpem@5 31471 const CImg<T>& save_bmp(cimg_std::FILE *const file) const {
philpem@5 31472 return _save_bmp(file,0);
philpem@5 31473 }
philpem@5 31474
philpem@5 31475 // Save a file in JPEG format (internal).
philpem@5 31476 const CImg<T>& _save_jpeg(cimg_std::FILE *const file, const char *const filename, const unsigned int quality) const {
philpem@5 31477 if (is_empty())
philpem@5 31478 throw CImgInstanceException("CImg<%s>::save_jpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31479 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31480 if (!file && !filename)
philpem@5 31481 throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 31482 pixel_type(),width,height,depth,dim,data);
philpem@5 31483 if (depth>1)
philpem@5 31484 cimg::warn("CImg<%s>::save_jpeg() : File '%s, instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
philpem@5 31485 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31486 #ifndef cimg_use_jpeg
philpem@5 31487 if (!file) return save_other(filename,quality);
philpem@5 31488 else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.",
philpem@5 31489 pixel_type());
philpem@5 31490 #else
philpem@5 31491 // Fill pixel buffer
philpem@5 31492 unsigned char *buf;
philpem@5 31493 unsigned int dimbuf = 0;
philpem@5 31494 J_COLOR_SPACE colortype = JCS_RGB;
philpem@5 31495 switch (dim) {
philpem@5 31496 case 1 : { // Greyscale images
philpem@5 31497 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)];
philpem@5 31498 colortype = JCS_GRAYSCALE;
philpem@5 31499 const T *ptr_g = data;
philpem@5 31500 cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++);
philpem@5 31501 } break;
philpem@5 31502 case 2 : { // RG images
philpem@5 31503 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
philpem@5 31504 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1);
philpem@5 31505 colortype = JCS_RGB;
philpem@5 31506 cimg_forXY(*this,x,y) {
philpem@5 31507 *(buf2++) = (unsigned char)*(ptr_r++);
philpem@5 31508 *(buf2++) = (unsigned char)*(ptr_g++);
philpem@5 31509 *(buf2++) = 0;
philpem@5 31510 }
philpem@5 31511 } break;
philpem@5 31512 case 3 : { // RGB images
philpem@5 31513 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)];
philpem@5 31514 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2);
philpem@5 31515 colortype = JCS_RGB;
philpem@5 31516 cimg_forXY(*this,x,y) {
philpem@5 31517 *(buf2++) = (unsigned char)*(ptr_r++);
philpem@5 31518 *(buf2++) = (unsigned char)*(ptr_g++);
philpem@5 31519 *(buf2++) = (unsigned char)*(ptr_b++);
philpem@5 31520 }
philpem@5 31521 } break;
philpem@5 31522 default : { // CMYK images
philpem@5 31523 unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)];
philpem@5 31524 const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,2), *ptr_a = ptr(0,0,0,3);
philpem@5 31525 colortype = JCS_CMYK;
philpem@5 31526 cimg_forXY(*this,x,y) {
philpem@5 31527 *(buf2++) = (unsigned char)*(ptr_r++);
philpem@5 31528 *(buf2++) = (unsigned char)*(ptr_g++);
philpem@5 31529 *(buf2++) = (unsigned char)*(ptr_b++);
philpem@5 31530 *(buf2++) = (unsigned char)*(ptr_a++);
philpem@5 31531 }
philpem@5 31532 }
philpem@5 31533 }
philpem@5 31534
philpem@5 31535 // Call libjpeg functions
philpem@5 31536 struct jpeg_compress_struct cinfo;
philpem@5 31537 struct jpeg_error_mgr jerr;
philpem@5 31538 cinfo.err = jpeg_std_error(&jerr);
philpem@5 31539 jpeg_create_compress(&cinfo);
philpem@5 31540 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 31541 jpeg_stdio_dest(&cinfo,nfile);
philpem@5 31542 cinfo.image_width = width;
philpem@5 31543 cinfo.image_height = height;
philpem@5 31544 cinfo.input_components = dimbuf;
philpem@5 31545 cinfo.in_color_space = colortype;
philpem@5 31546 jpeg_set_defaults(&cinfo);
philpem@5 31547 jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE);
philpem@5 31548 jpeg_start_compress(&cinfo,TRUE);
philpem@5 31549
philpem@5 31550 const unsigned int row_stride = width*dimbuf;
philpem@5 31551 JSAMPROW row_pointer[1];
philpem@5 31552 while (cinfo.next_scanline < cinfo.image_height) {
philpem@5 31553 row_pointer[0] = &buf[cinfo.next_scanline*row_stride];
philpem@5 31554 jpeg_write_scanlines(&cinfo,row_pointer,1);
philpem@5 31555 }
philpem@5 31556 jpeg_finish_compress(&cinfo);
philpem@5 31557
philpem@5 31558 delete[] buf;
philpem@5 31559 if (!file) cimg::fclose(nfile);
philpem@5 31560 jpeg_destroy_compress(&cinfo);
philpem@5 31561 return *this;
philpem@5 31562 #endif
philpem@5 31563 }
philpem@5 31564
philpem@5 31565 //! Save a file in JPEG format.
philpem@5 31566 const CImg<T>& save_jpeg(const char *const filename, const unsigned int quality=100) const {
philpem@5 31567 return _save_jpeg(0,filename,quality);
philpem@5 31568 }
philpem@5 31569
philpem@5 31570 //! Save a file in JPEG format.
philpem@5 31571 const CImg<T>& save_jpeg(cimg_std::FILE *const file, const unsigned int quality=100) const {
philpem@5 31572 return _save_jpeg(file,0,quality);
philpem@5 31573 }
philpem@5 31574
philpem@5 31575 //! Save the image using built-in ImageMagick++ library.
philpem@5 31576 const CImg<T>& save_magick(const char *const filename) const {
philpem@5 31577 if (is_empty())
philpem@5 31578 throw CImgInstanceException("CImg<%s>::save_magick() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31579 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 31580 if (!filename)
philpem@5 31581 throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31582 pixel_type(),width,height,depth,dim,data);
philpem@5 31583 #ifdef cimg_use_magick
philpem@5 31584 Magick::Image image(Magick::Geometry(width,height),"black");
philpem@5 31585 image.type(Magick::TrueColorType);
philpem@5 31586 const T
philpem@5 31587 *rdata = ptr(0,0,0,0),
philpem@5 31588 *gdata = dim>1?ptr(0,0,0,1):0,
philpem@5 31589 *bdata = dim>2?ptr(0,0,0,2):0;
philpem@5 31590 Magick::PixelPacket *pixels = image.getPixels(0,0,width,height);
philpem@5 31591 switch (dim) {
philpem@5 31592 case 1 : // Scalar images
philpem@5 31593 for (unsigned int off = width*height; off; --off) {
philpem@5 31594 pixels->red = pixels->green = pixels->blue = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
philpem@5 31595 ++pixels;
philpem@5 31596 }
philpem@5 31597 break;
philpem@5 31598 case 2 : // RG images
philpem@5 31599 for (unsigned int off = width*height; off; --off) {
philpem@5 31600 pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
philpem@5 31601 pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
philpem@5 31602 pixels->blue = 0;
philpem@5 31603 ++pixels;
philpem@5 31604 }
philpem@5 31605 break;
philpem@5 31606 default : // RGB images
philpem@5 31607 for (unsigned int off = width*height; off; --off) {
philpem@5 31608 pixels->red = Magick::Color::scaleDoubleToQuantum(*(rdata++)/255.0);
philpem@5 31609 pixels->green = Magick::Color::scaleDoubleToQuantum(*(gdata++)/255.0);
philpem@5 31610 pixels->blue = Magick::Color::scaleDoubleToQuantum(*(bdata++)/255.0);
philpem@5 31611 ++pixels;
philpem@5 31612 }
philpem@5 31613 }
philpem@5 31614 image.syncPixels();
philpem@5 31615 image.write(filename);
philpem@5 31616 #else
philpem@5 31617 throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.",
philpem@5 31618 pixel_type(),filename);
philpem@5 31619 #endif
philpem@5 31620 return *this;
philpem@5 31621 }
philpem@5 31622
philpem@5 31623 // Save an image to a PNG file (internal).
philpem@5 31624 // Most of this function has been written by Eric Fausett
philpem@5 31625 const CImg<T>& _save_png(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31626 if (is_empty())
philpem@5 31627 throw CImgInstanceException("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31628 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31629 if (!filename)
philpem@5 31630 throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 31631 pixel_type(),width,height,depth,dim,data);
philpem@5 31632 if (depth>1)
philpem@5 31633 cimg::warn("CImg<%s>::save_png() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
philpem@5 31634 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31635 #ifndef cimg_use_png
philpem@5 31636 if (!file) return save_other(filename);
philpem@5 31637 else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. You must use 'libpng' to do this instead.",
philpem@5 31638 pixel_type());
philpem@5 31639 #else
philpem@5 31640 const char *volatile nfilename = filename; // two 'volatile' here to remove a g++ warning due to 'setjmp'.
philpem@5 31641 cimg_std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb");
philpem@5 31642
philpem@5 31643 // Setup PNG structures for write
philpem@5 31644 png_voidp user_error_ptr = 0;
philpem@5 31645 png_error_ptr user_error_fn = 0, user_warning_fn = 0;
philpem@5 31646 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, user_warning_fn);
philpem@5 31647 if(!png_ptr){
philpem@5 31648 if (!file) cimg::fclose(nfile);
philpem@5 31649 throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.",
philpem@5 31650 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 31651 }
philpem@5 31652 png_infop info_ptr = png_create_info_struct(png_ptr);
philpem@5 31653 if (!info_ptr) {
philpem@5 31654 png_destroy_write_struct(&png_ptr,(png_infopp)0);
philpem@5 31655 if (!file) cimg::fclose(nfile);
philpem@5 31656 throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.",
philpem@5 31657 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 31658 }
philpem@5 31659 if (setjmp(png_jmpbuf(png_ptr))) {
philpem@5 31660 png_destroy_write_struct(&png_ptr, &info_ptr);
philpem@5 31661 if (!file) cimg::fclose(nfile);
philpem@5 31662 throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
philpem@5 31663 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 31664 }
philpem@5 31665 png_init_io(png_ptr, nfile);
philpem@5 31666 png_uint_32 width = dimx(), height = dimy();
philpem@5 31667 float vmin, vmax = (float)maxmin(vmin);
philpem@5 31668 const int bit_depth = (vmin<0 || vmax>=256)?16:8;
philpem@5 31669 int color_type;
philpem@5 31670 switch (dimv()) {
philpem@5 31671 case 1 : color_type = PNG_COLOR_TYPE_GRAY; break;
philpem@5 31672 case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
philpem@5 31673 case 3 : color_type = PNG_COLOR_TYPE_RGB; break;
philpem@5 31674 default : color_type = PNG_COLOR_TYPE_RGB_ALPHA;
philpem@5 31675 }
philpem@5 31676 const int interlace_type = PNG_INTERLACE_NONE;
philpem@5 31677 const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT;
philpem@5 31678 const int filter_method = PNG_FILTER_TYPE_DEFAULT;
philpem@5 31679 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type,compression_type, filter_method);
philpem@5 31680 png_write_info(png_ptr, info_ptr);
philpem@5 31681 const int byte_depth = bit_depth>>3;
philpem@5 31682 const int numChan = dimv()>4?4:dimv();
philpem@5 31683 const int pixel_bit_depth_flag = numChan * (bit_depth-1);
philpem@5 31684
philpem@5 31685 // Allocate Memory for Image Save and Fill pixel data
philpem@5 31686 png_bytep *imgData = new png_byte*[height];
philpem@5 31687 for (unsigned int row = 0; row<height; ++row) imgData[row] = new png_byte[byte_depth*numChan*width];
philpem@5 31688 const T *pC0 = ptr(0,0,0,0);
philpem@5 31689 switch (pixel_bit_depth_flag) {
philpem@5 31690 case 7 : { // Gray 8-bit
philpem@5 31691 cimg_forY(*this,y) {
philpem@5 31692 unsigned char *ptrd = imgData[y];
philpem@5 31693 cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++);
philpem@5 31694 }
philpem@5 31695 } break;
philpem@5 31696 case 14 : { // Gray w/ Alpha 8-bit
philpem@5 31697 const T *pC1 = ptr(0,0,0,1);
philpem@5 31698 cimg_forY(*this,y) {
philpem@5 31699 unsigned char *ptrd = imgData[y];
philpem@5 31700 cimg_forX(*this,x) {
philpem@5 31701 *(ptrd++) = (unsigned char)*(pC0++);
philpem@5 31702 *(ptrd++) = (unsigned char)*(pC1++);
philpem@5 31703 }
philpem@5 31704 }
philpem@5 31705 } break;
philpem@5 31706 case 21 : { // RGB 8-bit
philpem@5 31707 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
philpem@5 31708 cimg_forY(*this,y) {
philpem@5 31709 unsigned char *ptrd = imgData[y];
philpem@5 31710 cimg_forX(*this,x) {
philpem@5 31711 *(ptrd++) = (unsigned char)*(pC0++);
philpem@5 31712 *(ptrd++) = (unsigned char)*(pC1++);
philpem@5 31713 *(ptrd++) = (unsigned char)*(pC2++);
philpem@5 31714 }
philpem@5 31715 }
philpem@5 31716 } break;
philpem@5 31717 case 28 : { // RGB x/ Alpha 8-bit
philpem@5 31718 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
philpem@5 31719 cimg_forY(*this,y){
philpem@5 31720 unsigned char *ptrd = imgData[y];
philpem@5 31721 cimg_forX(*this,x){
philpem@5 31722 *(ptrd++) = (unsigned char)*(pC0++);
philpem@5 31723 *(ptrd++) = (unsigned char)*(pC1++);
philpem@5 31724 *(ptrd++) = (unsigned char)*(pC2++);
philpem@5 31725 *(ptrd++) = (unsigned char)*(pC3++);
philpem@5 31726 }
philpem@5 31727 }
philpem@5 31728 } break;
philpem@5 31729 case 15 : { // Gray 16-bit
philpem@5 31730 cimg_forY(*this,y){
philpem@5 31731 unsigned short *ptrd = (unsigned short*)(imgData[y]);
philpem@5 31732 cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++);
philpem@5 31733 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],width);
philpem@5 31734 }
philpem@5 31735 } break;
philpem@5 31736 case 30 : { // Gray w/ Alpha 16-bit
philpem@5 31737 const T *pC1 = ptr(0,0,0,1);
philpem@5 31738 cimg_forY(*this,y){
philpem@5 31739 unsigned short *ptrd = (unsigned short*)(imgData[y]);
philpem@5 31740 cimg_forX(*this,x) {
philpem@5 31741 *(ptrd++) = (unsigned short)*(pC0++);
philpem@5 31742 *(ptrd++) = (unsigned short)*(pC1++);
philpem@5 31743 }
philpem@5 31744 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*width);
philpem@5 31745 }
philpem@5 31746 } break;
philpem@5 31747 case 45 : { // RGB 16-bit
philpem@5 31748 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2);
philpem@5 31749 cimg_forY(*this,y) {
philpem@5 31750 unsigned short *ptrd = (unsigned short*)(imgData[y]);
philpem@5 31751 cimg_forX(*this,x) {
philpem@5 31752 *(ptrd++) = (unsigned short)*(pC0++);
philpem@5 31753 *(ptrd++) = (unsigned short)*(pC1++);
philpem@5 31754 *(ptrd++) = (unsigned short)*(pC2++);
philpem@5 31755 }
philpem@5 31756 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*width);
philpem@5 31757 }
philpem@5 31758 } break;
philpem@5 31759 case 60 : { // RGB w/ Alpha 16-bit
philpem@5 31760 const T *pC1 = ptr(0,0,0,1), *pC2 = ptr(0,0,0,2), *pC3 = ptr(0,0,0,3);
philpem@5 31761 cimg_forY(*this,y) {
philpem@5 31762 unsigned short *ptrd = (unsigned short*)(imgData[y]);
philpem@5 31763 cimg_forX(*this,x) {
philpem@5 31764 *(ptrd++) = (unsigned short)*(pC0++);
philpem@5 31765 *(ptrd++) = (unsigned short)*(pC1++);
philpem@5 31766 *(ptrd++) = (unsigned short)*(pC2++);
philpem@5 31767 *(ptrd++) = (unsigned short)*(pC3++);
philpem@5 31768 }
philpem@5 31769 if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*width);
philpem@5 31770 }
philpem@5 31771 } break;
philpem@5 31772 default :
philpem@5 31773 if (!file) cimg::fclose(nfile);
philpem@5 31774 throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.",
philpem@5 31775 pixel_type(),nfilename?nfilename:"(FILE*)");
philpem@5 31776 }
philpem@5 31777 png_write_image(png_ptr, imgData);
philpem@5 31778 png_write_end(png_ptr, info_ptr);
philpem@5 31779 png_destroy_write_struct(&png_ptr, &info_ptr);
philpem@5 31780
philpem@5 31781 // Deallocate Image Write Memory
philpem@5 31782 cimg_forY(*this,n) delete[] imgData[n];
philpem@5 31783 delete[] imgData;
philpem@5 31784 if (!file) cimg::fclose(nfile);
philpem@5 31785 return *this;
philpem@5 31786 #endif
philpem@5 31787 }
philpem@5 31788
philpem@5 31789 //! Save a file in PNG format
philpem@5 31790 const CImg<T>& save_png(const char *const filename) const {
philpem@5 31791 return _save_png(0,filename);
philpem@5 31792 }
philpem@5 31793
philpem@5 31794 //! Save a file in PNG format
philpem@5 31795 const CImg<T>& save_png(cimg_std::FILE *const file) const {
philpem@5 31796 return _save_png(file,0);
philpem@5 31797 }
philpem@5 31798
philpem@5 31799 // Save the image as a PNM file (internal function).
philpem@5 31800 const CImg<T>& _save_pnm(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31801 if (!file && !filename)
philpem@5 31802 throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31803 pixel_type(),width,height,depth,dim,data);
philpem@5 31804 if (is_empty())
philpem@5 31805 throw CImgInstanceException("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31806 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31807 double stmin, stmax = (double)maxmin(stmin);
philpem@5 31808 if (depth>1)
philpem@5 31809 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved.",
philpem@5 31810 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31811 if (dim>3)
philpem@5 31812 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved.",
philpem@5 31813 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31814 if (stmin<0 || stmax>65535)
philpem@5 31815 cimg::warn("CImg<%s>::save_pnm() : File '%s', instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow.",
philpem@5 31816 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data,stmin,stmax);
philpem@5 31817 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 31818 const T
philpem@5 31819 *ptrR = ptr(0,0,0,0),
philpem@5 31820 *ptrG = (dim>=2)?ptr(0,0,0,1):0,
philpem@5 31821 *ptrB = (dim>=3)?ptr(0,0,0,2):0;
philpem@5 31822 const unsigned int buf_size = width*height*(dim==1?1:3);
philpem@5 31823
philpem@5 31824 cimg_std::fprintf(nfile,"P%c\n# CREATOR: CImg Library (original size = %ux%ux%ux%u)\n%u %u\n%u\n",
philpem@5 31825 (dim==1?'5':'6'),width,height,depth,dim,width,height,stmax<256?255:(stmax<4096?4095:65535));
philpem@5 31826
philpem@5 31827 switch (dim) {
philpem@5 31828 case 1 : { // Scalar image
philpem@5 31829 if (stmax<256) { // Binary PGM 8 bits
philpem@5 31830 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
philpem@5 31831 cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++);
philpem@5 31832 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31833 delete[] ptrd;
philpem@5 31834 } else { // Binary PGM 16 bits
philpem@5 31835 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
philpem@5 31836 cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++);
philpem@5 31837 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
philpem@5 31838 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31839 delete[] ptrd;
philpem@5 31840 }
philpem@5 31841 } break;
philpem@5 31842 case 2 : { // RG image
philpem@5 31843 if (stmax<256) { // Binary PPM 8 bits
philpem@5 31844 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
philpem@5 31845 cimg_forXY(*this,x,y) {
philpem@5 31846 *(xptrd++) = (unsigned char)*(ptrR++);
philpem@5 31847 *(xptrd++) = (unsigned char)*(ptrG++);
philpem@5 31848 *(xptrd++) = 0;
philpem@5 31849 }
philpem@5 31850 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31851 delete[] ptrd;
philpem@5 31852 } else { // Binary PPM 16 bits
philpem@5 31853 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
philpem@5 31854 cimg_forXY(*this,x,y) {
philpem@5 31855 *(xptrd++) = (unsigned short)*(ptrR++);
philpem@5 31856 *(xptrd++) = (unsigned short)*(ptrG++);
philpem@5 31857 *(xptrd++) = 0;
philpem@5 31858 }
philpem@5 31859 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
philpem@5 31860 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31861 delete[] ptrd;
philpem@5 31862 }
philpem@5 31863 } break;
philpem@5 31864 default : { // RGB image
philpem@5 31865 if (stmax<256) { // Binary PPM 8 bits
philpem@5 31866 unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd;
philpem@5 31867 cimg_forXY(*this,x,y) {
philpem@5 31868 *(xptrd++) = (unsigned char)*(ptrR++);
philpem@5 31869 *(xptrd++) = (unsigned char)*(ptrG++);
philpem@5 31870 *(xptrd++) = (unsigned char)*(ptrB++);
philpem@5 31871 }
philpem@5 31872 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31873 delete[] ptrd;
philpem@5 31874 } else { // Binary PPM 16 bits
philpem@5 31875 unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd;
philpem@5 31876 cimg_forXY(*this,x,y) {
philpem@5 31877 *(xptrd++) = (unsigned short)*(ptrR++);
philpem@5 31878 *(xptrd++) = (unsigned short)*(ptrG++);
philpem@5 31879 *(xptrd++) = (unsigned short)*(ptrB++);
philpem@5 31880 }
philpem@5 31881 if (!cimg::endianness()) cimg::invert_endianness(ptrd,buf_size);
philpem@5 31882 cimg::fwrite(ptrd,buf_size,nfile);
philpem@5 31883 delete[] ptrd;
philpem@5 31884 }
philpem@5 31885 }
philpem@5 31886 }
philpem@5 31887 if (!file) cimg::fclose(nfile);
philpem@5 31888 return *this;
philpem@5 31889 }
philpem@5 31890
philpem@5 31891 //! Save the image as a PNM file.
philpem@5 31892 const CImg<T>& save_pnm(const char *const filename) const {
philpem@5 31893 return _save_pnm(0,filename);
philpem@5 31894 }
philpem@5 31895
philpem@5 31896 //! Save the image as a PNM file.
philpem@5 31897 const CImg<T>& save_pnm(cimg_std::FILE *const file) const {
philpem@5 31898 return _save_pnm(file,0);
philpem@5 31899 }
philpem@5 31900
philpem@5 31901 // Save the image as a RGB file (internal).
philpem@5 31902 const CImg<T>& _save_rgb(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31903 if (is_empty())
philpem@5 31904 throw CImgInstanceException("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31905 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31906 if (!file && !filename)
philpem@5 31907 throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31908 pixel_type(),width,height,depth,dim,data);
philpem@5 31909 if (dim!=3)
philpem@5 31910 cimg::warn("CImg<%s>::save_rgb() : File '%s', instance image (%u,%u,%u,%u,%p) has not exactly 3 channels.",
philpem@5 31911 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31912 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 31913 const unsigned int wh = width*height;
philpem@5 31914 unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer;
philpem@5 31915 const T
philpem@5 31916 *ptr1 = ptr(0,0,0,0),
philpem@5 31917 *ptr2 = dim>1?ptr(0,0,0,1):0,
philpem@5 31918 *ptr3 = dim>2?ptr(0,0,0,2):0;
philpem@5 31919 switch (dim) {
philpem@5 31920 case 1 : { // Scalar image
philpem@5 31921 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31922 const unsigned char val = (unsigned char)*(ptr1++);
philpem@5 31923 *(nbuffer++) = val;
philpem@5 31924 *(nbuffer++) = val;
philpem@5 31925 *(nbuffer++) = val;
philpem@5 31926 }} break;
philpem@5 31927 case 2 : { // RG image
philpem@5 31928 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31929 *(nbuffer++) = (unsigned char)(*(ptr1++));
philpem@5 31930 *(nbuffer++) = (unsigned char)(*(ptr2++));
philpem@5 31931 *(nbuffer++) = 0;
philpem@5 31932 }} break;
philpem@5 31933 default : { // RGB image
philpem@5 31934 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31935 *(nbuffer++) = (unsigned char)(*(ptr1++));
philpem@5 31936 *(nbuffer++) = (unsigned char)(*(ptr2++));
philpem@5 31937 *(nbuffer++) = (unsigned char)(*(ptr3++));
philpem@5 31938 }
philpem@5 31939 }
philpem@5 31940 }
philpem@5 31941 cimg::fwrite(buffer,3*wh,nfile);
philpem@5 31942 if (!file) cimg::fclose(nfile);
philpem@5 31943 delete[] buffer;
philpem@5 31944 return *this;
philpem@5 31945 }
philpem@5 31946
philpem@5 31947 //! Save the image as a RGB file.
philpem@5 31948 const CImg<T>& save_rgb(const char *const filename) const {
philpem@5 31949 return _save_rgb(0,filename);
philpem@5 31950 }
philpem@5 31951
philpem@5 31952 //! Save the image as a RGB file.
philpem@5 31953 const CImg<T>& save_rgb(cimg_std::FILE *const file) const {
philpem@5 31954 return _save_rgb(file,0);
philpem@5 31955 }
philpem@5 31956
philpem@5 31957 // Save the image as a RGBA file (internal).
philpem@5 31958 const CImg<T>& _save_rgba(cimg_std::FILE *const file, const char *const filename) const {
philpem@5 31959 if (is_empty())
philpem@5 31960 throw CImgInstanceException("CImg<%s>::save_rgba() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 31961 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31962 if (!file && !filename)
philpem@5 31963 throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 31964 pixel_type(),width,height,depth,dim,data);
philpem@5 31965 if (dim!=4)
philpem@5 31966 cimg::warn("CImg<%s>::save_rgba() : File '%s, instance image (%u,%u,%u,%u,%p) has not exactly 4 channels.",
philpem@5 31967 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 31968 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 31969 const unsigned int wh = width*height;
philpem@5 31970 unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer;
philpem@5 31971 const T
philpem@5 31972 *ptr1 = ptr(0,0,0,0),
philpem@5 31973 *ptr2 = dim>1?ptr(0,0,0,1):0,
philpem@5 31974 *ptr3 = dim>2?ptr(0,0,0,2):0,
philpem@5 31975 *ptr4 = dim>3?ptr(0,0,0,3):0;
philpem@5 31976 switch (dim) {
philpem@5 31977 case 1 : { // Scalar images
philpem@5 31978 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31979 const unsigned char val = (unsigned char)*(ptr1++);
philpem@5 31980 *(nbuffer++) = val;
philpem@5 31981 *(nbuffer++) = val;
philpem@5 31982 *(nbuffer++) = val;
philpem@5 31983 *(nbuffer++) = 255;
philpem@5 31984 }} break;
philpem@5 31985 case 2 : { // RG images
philpem@5 31986 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31987 *(nbuffer++) = (unsigned char)(*(ptr1++));
philpem@5 31988 *(nbuffer++) = (unsigned char)(*(ptr2++));
philpem@5 31989 *(nbuffer++) = 0;
philpem@5 31990 *(nbuffer++) = 255;
philpem@5 31991 }} break;
philpem@5 31992 case 3 : { // RGB images
philpem@5 31993 for (unsigned int k=0; k<wh; ++k) {
philpem@5 31994 *(nbuffer++) = (unsigned char)(*(ptr1++));
philpem@5 31995 *(nbuffer++) = (unsigned char)(*(ptr2++));
philpem@5 31996 *(nbuffer++) = (unsigned char)(*(ptr3++));
philpem@5 31997 *(nbuffer++) = 255;
philpem@5 31998 }} break;
philpem@5 31999 default : { // RGBA images
philpem@5 32000 for (unsigned int k=0; k<wh; ++k) {
philpem@5 32001 *(nbuffer++) = (unsigned char)(*(ptr1++));
philpem@5 32002 *(nbuffer++) = (unsigned char)(*(ptr2++));
philpem@5 32003 *(nbuffer++) = (unsigned char)(*(ptr3++));
philpem@5 32004 *(nbuffer++) = (unsigned char)(*(ptr4++));
philpem@5 32005 }
philpem@5 32006 }
philpem@5 32007 }
philpem@5 32008 cimg::fwrite(buffer,4*wh,nfile);
philpem@5 32009 if (!file) cimg::fclose(nfile);
philpem@5 32010 delete[] buffer;
philpem@5 32011 return *this;
philpem@5 32012 }
philpem@5 32013
philpem@5 32014 //! Save the image as a RGBA file.
philpem@5 32015 const CImg<T>& save_rgba(const char *const filename) const {
philpem@5 32016 return _save_rgba(0,filename);
philpem@5 32017 }
philpem@5 32018
philpem@5 32019 //! Save the image as a RGBA file.
philpem@5 32020 const CImg<T>& save_rgba(cimg_std::FILE *const file) const {
philpem@5 32021 return _save_rgba(file,0);
philpem@5 32022 }
philpem@5 32023
philpem@5 32024 // Save a plane into a tiff file
philpem@5 32025 #ifdef cimg_use_tiff
philpem@5 32026 const CImg<T>& _save_tiff(TIFF *tif, const unsigned int directory) const {
philpem@5 32027 if (is_empty() || !tif) return *this;
philpem@5 32028 const char *const filename = TIFFFileName(tif);
philpem@5 32029 uint32 rowsperstrip = (uint32)-1;
philpem@5 32030 uint16 spp = dim, bpp = sizeof(T)*8, photometric, compression = COMPRESSION_NONE;
philpem@5 32031 if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB;
philpem@5 32032 else photometric = PHOTOMETRIC_MINISBLACK;
philpem@5 32033 TIFFSetDirectory(tif,directory);
philpem@5 32034 TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,width);
philpem@5 32035 TIFFSetField(tif,TIFFTAG_IMAGELENGTH,height);
philpem@5 32036 TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
philpem@5 32037 TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp);
philpem@5 32038 if (cimg::type<T>::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3);
philpem@5 32039 else if (cimg::type<T>::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1);
philpem@5 32040 else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2);
philpem@5 32041 TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp);
philpem@5 32042 TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
philpem@5 32043 TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric);
philpem@5 32044 TIFFSetField(tif,TIFFTAG_COMPRESSION,compression);
philpem@5 32045 rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip);
philpem@5 32046 TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
philpem@5 32047 TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB);
philpem@5 32048 TIFFSetField(tif,TIFFTAG_SOFTWARE,"CImg");
philpem@5 32049 T *buf = (T*)_TIFFmalloc(TIFFStripSize(tif));
philpem@5 32050 if (buf){
philpem@5 32051 for (unsigned int row = 0; row<height; row+=rowsperstrip) {
philpem@5 32052 uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip);
philpem@5 32053 tstrip_t strip = TIFFComputeStrip(tif,row,0);
philpem@5 32054 tsize_t i = 0;
philpem@5 32055 for (unsigned int rr = 0; rr<nrow; ++rr)
philpem@5 32056 for (unsigned int cc = 0; cc<width; ++cc)
philpem@5 32057 for (unsigned int vv = 0; vv<spp; ++vv)
philpem@5 32058 buf[i++] = (*this)(cc,row+rr,vv);
philpem@5 32059 if (TIFFWriteEncodedStrip(tif,strip,buf,i*sizeof(T))<0)
philpem@5 32060 throw CImgException("CImg<%s>::save_tiff() : File '%s', an error has occured while writing a strip.",
philpem@5 32061 pixel_type(),filename?filename:"(FILE*)");
philpem@5 32062 }
philpem@5 32063 _TIFFfree(buf);
philpem@5 32064 }
philpem@5 32065 TIFFWriteDirectory(tif);
philpem@5 32066 return (*this);
philpem@5 32067 }
philpem@5 32068 #endif
philpem@5 32069
philpem@5 32070 //! Save a file in TIFF format.
philpem@5 32071 const CImg<T>& save_tiff(const char *const filename) const {
philpem@5 32072 if (is_empty())
philpem@5 32073 throw CImgInstanceException("CImg<%s>::save_tiff() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32074 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32075 if (!filename)
philpem@5 32076 throw CImgArgumentException("CImg<%s>::save_tiff() : Specified filename is (null) for instance image (%u,%u,%u,%u,%p).",
philpem@5 32077 pixel_type(),width,height,depth,dim,data);
philpem@5 32078 #ifdef cimg_use_tiff
philpem@5 32079 TIFF *tif = TIFFOpen(filename,"w");
philpem@5 32080 if (tif) {
philpem@5 32081 cimg_forZ(*this,z) get_slice(z)._save_tiff(tif,z);
philpem@5 32082 TIFFClose(tif);
philpem@5 32083 } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while opening file stream for writing.",
philpem@5 32084 pixel_type(),filename);
philpem@5 32085 #else
philpem@5 32086 return save_other(filename);
philpem@5 32087 #endif
philpem@5 32088 return *this;
philpem@5 32089 }
philpem@5 32090
philpem@5 32091 //! Save the image as an ANALYZE7.5 or NIFTI file.
philpem@5 32092 const CImg<T>& save_analyze(const char *const filename, const float *const voxsize=0) const {
philpem@5 32093 if (is_empty())
philpem@5 32094 throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32095 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32096 if (!filename)
philpem@5 32097 throw CImgArgumentException("CImg<%s>::save_analyze() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32098 pixel_type(),width,height,depth,dim,data);
philpem@5 32099 cimg_std::FILE *file;
philpem@5 32100 char header[348], hname[1024], iname[1024];
philpem@5 32101 const char *ext = cimg::split_filename(filename);
philpem@5 32102 short datatype=-1;
philpem@5 32103 cimg_std::memset(header,0,348);
philpem@5 32104 if (!ext[0]) { cimg_std::sprintf(hname,"%s.hdr",filename); cimg_std::sprintf(iname,"%s.img",filename); }
philpem@5 32105 if (!cimg::strncasecmp(ext,"hdr",3)) {
philpem@5 32106 cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(iname+cimg::strlen(iname)-3,"img");
philpem@5 32107 }
philpem@5 32108 if (!cimg::strncasecmp(ext,"img",3)) {
philpem@5 32109 cimg_std::strcpy(hname,filename); cimg_std::strcpy(iname,filename); cimg_std::sprintf(hname+cimg::strlen(iname)-3,"hdr");
philpem@5 32110 }
philpem@5 32111 if (!cimg::strncasecmp(ext,"nii",3)) {
philpem@5 32112 cimg_std::strcpy(hname,filename); iname[0] = 0;
philpem@5 32113 }
philpem@5 32114 ((int*)(header))[0] = 348;
philpem@5 32115 cimg_std::sprintf(header+4,"CImg");
philpem@5 32116 cimg_std::sprintf(header+14," ");
philpem@5 32117 ((short*)(header+36))[0] = 4096;
philpem@5 32118 ((char*)(header+38))[0] = 114;
philpem@5 32119 ((short*)(header+40))[0] = 4;
philpem@5 32120 ((short*)(header+40))[1] = width;
philpem@5 32121 ((short*)(header+40))[2] = height;
philpem@5 32122 ((short*)(header+40))[3] = depth;
philpem@5 32123 ((short*)(header+40))[4] = dim;
philpem@5 32124 if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2;
philpem@5 32125 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2;
philpem@5 32126 if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2;
philpem@5 32127 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4;
philpem@5 32128 if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4;
philpem@5 32129 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8;
philpem@5 32130 if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8;
philpem@5 32131 if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8;
philpem@5 32132 if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8;
philpem@5 32133 if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16;
philpem@5 32134 if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64;
philpem@5 32135 if (datatype<0)
philpem@5 32136 throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)"
philpem@5 32137 "is not handled in Analyze7.5 specifications.\n",
philpem@5 32138 pixel_type(),filename,pixel_type());
philpem@5 32139 ((short*)(header+70))[0] = datatype;
philpem@5 32140 ((short*)(header+72))[0] = sizeof(T);
philpem@5 32141 ((float*)(header+112))[0] = 1;
philpem@5 32142 ((float*)(header+76))[0] = 0;
philpem@5 32143 if (voxsize) {
philpem@5 32144 ((float*)(header+76))[1] = voxsize[0];
philpem@5 32145 ((float*)(header+76))[2] = voxsize[1];
philpem@5 32146 ((float*)(header+76))[3] = voxsize[2];
philpem@5 32147 } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1;
philpem@5 32148 file = cimg::fopen(hname,"wb");
philpem@5 32149 cimg::fwrite(header,348,file);
philpem@5 32150 if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); }
philpem@5 32151 cimg::fwrite(data,size(),file);
philpem@5 32152 cimg::fclose(file);
philpem@5 32153 return *this;
philpem@5 32154 }
philpem@5 32155
philpem@5 32156 //! Save the image as a .cimg file.
philpem@5 32157 const CImg<T>& save_cimg(const char *const filename, const bool compress=false) const {
philpem@5 32158 CImgList<T>(*this,true).save_cimg(filename,compress);
philpem@5 32159 return *this;
philpem@5 32160 }
philpem@5 32161
philpem@5 32162 // Save the image as a .cimg file.
philpem@5 32163 const CImg<T>& save_cimg(cimg_std::FILE *const file, const bool compress=false) const {
philpem@5 32164 CImgList<T>(*this,true).save_cimg(file,compress);
philpem@5 32165 return *this;
philpem@5 32166 }
philpem@5 32167
philpem@5 32168 //! Insert the image into an existing .cimg file, at specified coordinates.
philpem@5 32169 const CImg<T>& save_cimg(const char *const filename,
philpem@5 32170 const unsigned int n0,
philpem@5 32171 const unsigned int x0, const unsigned int y0,
philpem@5 32172 const unsigned int z0, const unsigned int v0) const {
philpem@5 32173 CImgList<T>(*this,true).save_cimg(filename,n0,x0,y0,z0,v0);
philpem@5 32174 return *this;
philpem@5 32175 }
philpem@5 32176
philpem@5 32177 //! Insert the image into an existing .cimg file, at specified coordinates.
philpem@5 32178 const CImg<T>& save_cimg(cimg_std::FILE *const file,
philpem@5 32179 const unsigned int n0,
philpem@5 32180 const unsigned int x0, const unsigned int y0,
philpem@5 32181 const unsigned int z0, const unsigned int v0) const {
philpem@5 32182 CImgList<T>(*this,true).save_cimg(file,n0,x0,y0,z0,v0);
philpem@5 32183 return *this;
philpem@5 32184 }
philpem@5 32185
philpem@5 32186 //! Save an empty .cimg file with specified dimensions.
philpem@5 32187 static void save_empty_cimg(const char *const filename,
philpem@5 32188 const unsigned int dx, const unsigned int dy=1,
philpem@5 32189 const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 32190 return CImgList<T>::save_empty_cimg(filename,1,dx,dy,dz,dv);
philpem@5 32191 }
philpem@5 32192
philpem@5 32193 //! Save an empty .cimg file with specified dimensions.
philpem@5 32194 static void save_empty_cimg(cimg_std::FILE *const file,
philpem@5 32195 const unsigned int dx, const unsigned int dy=1,
philpem@5 32196 const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 32197 return CImgList<T>::save_empty_cimg(file,1,dx,dy,dz,dv);
philpem@5 32198 }
philpem@5 32199
philpem@5 32200 // Save the image as an INRIMAGE-4 file (internal).
philpem@5 32201 const CImg<T>& _save_inr(cimg_std::FILE *const file, const char *const filename, const float *const voxsize) const {
philpem@5 32202 if (is_empty())
philpem@5 32203 throw CImgInstanceException("CImg<%s>::save_inr() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32204 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 32205 if (!filename)
philpem@5 32206 throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 32207 pixel_type(),width,height,depth,dim,data);
philpem@5 32208 int inrpixsize=-1;
philpem@5 32209 const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0";
philpem@5 32210 if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
philpem@5 32211 if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; }
philpem@5 32212 if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; }
philpem@5 32213 if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; }
philpem@5 32214 if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; }
philpem@5 32215 if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; }
philpem@5 32216 if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; }
philpem@5 32217 if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; }
philpem@5 32218 if (inrpixsize<=0)
philpem@5 32219 throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",
philpem@5 32220 pixel_type(),pixel_type());
philpem@5 32221 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 32222 char header[257];
philpem@5 32223 int err = cimg_std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim);
philpem@5 32224 if (voxsize) err += cimg_std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]);
philpem@5 32225 err += cimg_std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm");
philpem@5 32226 cimg_std::memset(header+err,'\n',252-err);
philpem@5 32227 cimg_std::memcpy(header+252,"##}\n",4);
philpem@5 32228 cimg::fwrite(header,256,nfile);
philpem@5 32229 cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile);
philpem@5 32230 if (!file) cimg::fclose(nfile);
philpem@5 32231 return *this;
philpem@5 32232 }
philpem@5 32233
philpem@5 32234 //! Save the image as an INRIMAGE-4 file.
philpem@5 32235 const CImg<T>& save_inr(const char *const filename, const float *const voxsize=0) const {
philpem@5 32236 return _save_inr(0,filename,voxsize);
philpem@5 32237 }
philpem@5 32238
philpem@5 32239 //! Save the image as an INRIMAGE-4 file.
philpem@5 32240 const CImg<T>& save_inr(cimg_std::FILE *const file, const float *const voxsize=0) const {
philpem@5 32241 return _save_inr(file,0,voxsize);
philpem@5 32242 }
philpem@5 32243
philpem@5 32244 // Save the image as a PANDORE-5 file (internal).
philpem@5 32245 unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const {
philpem@5 32246 unsigned int nbdims = 0;
philpem@5 32247 if (id==2 || id==3 || id==4) { dims[0] = 1; dims[1] = width; nbdims = 2; }
philpem@5 32248 if (id==5 || id==6 || id==7) { dims[0] = 1; dims[1] = height; dims[2] = width; nbdims=3; }
philpem@5 32249 if (id==8 || id==9 || id==10) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
philpem@5 32250 if (id==16 || id==17 || id==18) { dims[0] = 3; dims[1] = height; dims[2] = width; dims[3] = colorspace; nbdims = 4; }
philpem@5 32251 if (id==19 || id==20 || id==21) { dims[0] = 3; dims[1] = depth; dims[2] = height; dims[3] = width; dims[4] = colorspace; nbdims = 5; }
philpem@5 32252 if (id==22 || id==23 || id==25) { dims[0] = dim; dims[1] = width; nbdims = 2; }
philpem@5 32253 if (id==26 || id==27 || id==29) { dims[0] = dim; dims[1] = height; dims[2] = width; nbdims=3; }
philpem@5 32254 if (id==30 || id==31 || id==33) { dims[0] = dim; dims[1] = depth; dims[2] = height; dims[3] = width; nbdims = 4; }
philpem@5 32255 return nbdims;
philpem@5 32256 }
philpem@5 32257
philpem@5 32258 const CImg<T>& _save_pandore(cimg_std::FILE *const file, const char *const filename, const unsigned int colorspace) const {
philpem@5 32259 typedef unsigned char uchar;
philpem@5 32260 typedef unsigned short ushort;
philpem@5 32261 typedef unsigned int uint;
philpem@5 32262 typedef unsigned long ulong;
philpem@5 32263
philpem@5 32264 #define __cimg_save_pandore_case(dtype) \
philpem@5 32265 dtype *buffer = new dtype[size()]; \
philpem@5 32266 const T *ptrs = data; \
philpem@5 32267 cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \
philpem@5 32268 buffer-=size(); \
philpem@5 32269 cimg::fwrite(buffer,size(),nfile); \
philpem@5 32270 delete[] buffer
philpem@5 32271
philpem@5 32272 #define _cimg_save_pandore_case(sy,sz,sv,stype,id) \
philpem@5 32273 if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !cimg::strcmp(stype,pixel_type())) { \
philpem@5 32274 unsigned int *iheader = (unsigned int*)(header+12); \
philpem@5 32275 nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \
philpem@5 32276 cimg::fwrite(header,36,nfile); \
philpem@5 32277 if (sizeof(ulong)==4) { ulong ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ulong)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
philpem@5 32278 else if (sizeof(uint)==4) { uint ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (uint)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
philpem@5 32279 else if (sizeof(ushort)==4) { ushort ndims[5]; for (int d = 0; d<5; ++d) ndims[d] = (ushort)dims[d]; cimg::fwrite(ndims,nbdims,nfile); } \
philpem@5 32280 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
philpem@5 32281 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
philpem@5 32282 depth,dim,data); \
philpem@5 32283 if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \
philpem@5 32284 __cimg_save_pandore_case(uchar); \
philpem@5 32285 } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \
philpem@5 32286 if (sizeof(ulong)==4) { __cimg_save_pandore_case(ulong); } \
philpem@5 32287 else if (sizeof(uint)==4) { __cimg_save_pandore_case(uint); } \
philpem@5 32288 else if (sizeof(ushort)==4) { __cimg_save_pandore_case(ushort); } \
philpem@5 32289 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
philpem@5 32290 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
philpem@5 32291 depth,dim,data); \
philpem@5 32292 } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \
philpem@5 32293 if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \
philpem@5 32294 else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \
philpem@5 32295 else throw CImgIOException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p), output type is not" \
philpem@5 32296 "supported on this architecture.",pixel_type(),filename?filename:"(FILE*)",width,height, \
philpem@5 32297 depth,dim,data); \
philpem@5 32298 } \
philpem@5 32299 saved = true; \
philpem@5 32300 }
philpem@5 32301
philpem@5 32302 if (is_empty())
philpem@5 32303 throw CImgInstanceException("CImg<%s>::save_pandore() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32304 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 32305 if (!file && !filename)
philpem@5 32306 throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 32307 pixel_type(),width,height,depth,dim,data);
philpem@5 32308 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 32309 unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0,
philpem@5 32310 0,0,0,0,'C','I','m','g',0,0,0,0,0,'N','o',' ','d','a','t','e',0,0,0,0 };
philpem@5 32311 unsigned int nbdims, dims[5];
philpem@5 32312 bool saved = false;
philpem@5 32313 _cimg_save_pandore_case(1,1,1,"unsigned char",2);
philpem@5 32314 _cimg_save_pandore_case(1,1,1,"char",3);
philpem@5 32315 _cimg_save_pandore_case(1,1,1,"short",3);
philpem@5 32316 _cimg_save_pandore_case(1,1,1,"unsigned short",3);
philpem@5 32317 _cimg_save_pandore_case(1,1,1,"unsigned int",3);
philpem@5 32318 _cimg_save_pandore_case(1,1,1,"int",3);
philpem@5 32319 _cimg_save_pandore_case(1,1,1,"unsigned long",4);
philpem@5 32320 _cimg_save_pandore_case(1,1,1,"long",3);
philpem@5 32321 _cimg_save_pandore_case(1,1,1,"float",4);
philpem@5 32322 _cimg_save_pandore_case(1,1,1,"double",4);
philpem@5 32323
philpem@5 32324 _cimg_save_pandore_case(0,1,1,"unsigned char",5);
philpem@5 32325 _cimg_save_pandore_case(0,1,1,"char",6);
philpem@5 32326 _cimg_save_pandore_case(0,1,1,"short",6);
philpem@5 32327 _cimg_save_pandore_case(0,1,1,"unsigned short",6);
philpem@5 32328 _cimg_save_pandore_case(0,1,1,"unsigned int",6);
philpem@5 32329 _cimg_save_pandore_case(0,1,1,"int",6);
philpem@5 32330 _cimg_save_pandore_case(0,1,1,"unsigned long",7);
philpem@5 32331 _cimg_save_pandore_case(0,1,1,"long",6);
philpem@5 32332 _cimg_save_pandore_case(0,1,1,"float",7);
philpem@5 32333 _cimg_save_pandore_case(0,1,1,"double",7);
philpem@5 32334
philpem@5 32335 _cimg_save_pandore_case(0,0,1,"unsigned char",8);
philpem@5 32336 _cimg_save_pandore_case(0,0,1,"char",9);
philpem@5 32337 _cimg_save_pandore_case(0,0,1,"short",9);
philpem@5 32338 _cimg_save_pandore_case(0,0,1,"unsigned short",9);
philpem@5 32339 _cimg_save_pandore_case(0,0,1,"unsigned int",9);
philpem@5 32340 _cimg_save_pandore_case(0,0,1,"int",9);
philpem@5 32341 _cimg_save_pandore_case(0,0,1,"unsigned long",10);
philpem@5 32342 _cimg_save_pandore_case(0,0,1,"long",9);
philpem@5 32343 _cimg_save_pandore_case(0,0,1,"float",10);
philpem@5 32344 _cimg_save_pandore_case(0,0,1,"double",10);
philpem@5 32345
philpem@5 32346 _cimg_save_pandore_case(0,1,3,"unsigned char",16);
philpem@5 32347 _cimg_save_pandore_case(0,1,3,"char",17);
philpem@5 32348 _cimg_save_pandore_case(0,1,3,"short",17);
philpem@5 32349 _cimg_save_pandore_case(0,1,3,"unsigned short",17);
philpem@5 32350 _cimg_save_pandore_case(0,1,3,"unsigned int",17);
philpem@5 32351 _cimg_save_pandore_case(0,1,3,"int",17);
philpem@5 32352 _cimg_save_pandore_case(0,1,3,"unsigned long",18);
philpem@5 32353 _cimg_save_pandore_case(0,1,3,"long",17);
philpem@5 32354 _cimg_save_pandore_case(0,1,3,"float",18);
philpem@5 32355 _cimg_save_pandore_case(0,1,3,"double",18);
philpem@5 32356
philpem@5 32357 _cimg_save_pandore_case(0,0,3,"unsigned char",19);
philpem@5 32358 _cimg_save_pandore_case(0,0,3,"char",20);
philpem@5 32359 _cimg_save_pandore_case(0,0,3,"short",20);
philpem@5 32360 _cimg_save_pandore_case(0,0,3,"unsigned short",20);
philpem@5 32361 _cimg_save_pandore_case(0,0,3,"unsigned int",20);
philpem@5 32362 _cimg_save_pandore_case(0,0,3,"int",20);
philpem@5 32363 _cimg_save_pandore_case(0,0,3,"unsigned long",21);
philpem@5 32364 _cimg_save_pandore_case(0,0,3,"long",20);
philpem@5 32365 _cimg_save_pandore_case(0,0,3,"float",21);
philpem@5 32366 _cimg_save_pandore_case(0,0,3,"double",21);
philpem@5 32367
philpem@5 32368 _cimg_save_pandore_case(1,1,0,"unsigned char",22);
philpem@5 32369 _cimg_save_pandore_case(1,1,0,"char",23);
philpem@5 32370 _cimg_save_pandore_case(1,1,0,"short",23);
philpem@5 32371 _cimg_save_pandore_case(1,1,0,"unsigned short",23);
philpem@5 32372 _cimg_save_pandore_case(1,1,0,"unsigned int",23);
philpem@5 32373 _cimg_save_pandore_case(1,1,0,"int",23);
philpem@5 32374 _cimg_save_pandore_case(1,1,0,"unsigned long",25);
philpem@5 32375 _cimg_save_pandore_case(1,1,0,"long",23);
philpem@5 32376 _cimg_save_pandore_case(1,1,0,"float",25);
philpem@5 32377 _cimg_save_pandore_case(1,1,0,"double",25);
philpem@5 32378
philpem@5 32379 _cimg_save_pandore_case(0,1,0,"unsigned char",26);
philpem@5 32380 _cimg_save_pandore_case(0,1,0,"char",27);
philpem@5 32381 _cimg_save_pandore_case(0,1,0,"short",27);
philpem@5 32382 _cimg_save_pandore_case(0,1,0,"unsigned short",27);
philpem@5 32383 _cimg_save_pandore_case(0,1,0,"unsigned int",27);
philpem@5 32384 _cimg_save_pandore_case(0,1,0,"int",27);
philpem@5 32385 _cimg_save_pandore_case(0,1,0,"unsigned long",29);
philpem@5 32386 _cimg_save_pandore_case(0,1,0,"long",27);
philpem@5 32387 _cimg_save_pandore_case(0,1,0,"float",29);
philpem@5 32388 _cimg_save_pandore_case(0,1,0,"double",29);
philpem@5 32389
philpem@5 32390 _cimg_save_pandore_case(0,0,0,"unsigned char",30);
philpem@5 32391 _cimg_save_pandore_case(0,0,0,"char",31);
philpem@5 32392 _cimg_save_pandore_case(0,0,0,"short",31);
philpem@5 32393 _cimg_save_pandore_case(0,0,0,"unsigned short",31);
philpem@5 32394 _cimg_save_pandore_case(0,0,0,"unsigned int",31);
philpem@5 32395 _cimg_save_pandore_case(0,0,0,"int",31);
philpem@5 32396 _cimg_save_pandore_case(0,0,0,"unsigned long",33);
philpem@5 32397 _cimg_save_pandore_case(0,0,0,"long",31);
philpem@5 32398 _cimg_save_pandore_case(0,0,0,"float",33);
philpem@5 32399 _cimg_save_pandore_case(0,0,0,"double",33);
philpem@5 32400
philpem@5 32401 if (!file) cimg::fclose(nfile);
philpem@5 32402 return *this;
philpem@5 32403 }
philpem@5 32404
philpem@5 32405 //! Save the image as a PANDORE-5 file.
philpem@5 32406 const CImg<T>& save_pandore(const char *const filename, const unsigned int colorspace=0) const {
philpem@5 32407 return _save_pandore(0,filename,colorspace);
philpem@5 32408 }
philpem@5 32409
philpem@5 32410 //! Save the image as a PANDORE-5 file.
philpem@5 32411 const CImg<T>& save_pandore(cimg_std::FILE *const file, const unsigned int colorspace=0) const {
philpem@5 32412 return _save_pandore(file,0,colorspace);
philpem@5 32413 }
philpem@5 32414
philpem@5 32415 // Save the image as a RAW file (internal).
philpem@5 32416 const CImg<T>& _save_raw(cimg_std::FILE *const file, const char *const filename, const bool multiplexed) const {
philpem@5 32417 if (is_empty())
philpem@5 32418 throw CImgInstanceException("CImg<%s>::save_raw() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32419 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 32420 if (!file && !filename)
philpem@5 32421 throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).",
philpem@5 32422 pixel_type(),width,height,depth,dim,data);
philpem@5 32423 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 32424 if (!multiplexed) cimg::fwrite(data,size(),nfile);
philpem@5 32425 else {
philpem@5 32426 CImg<T> buf(dim);
philpem@5 32427 cimg_forXYZ(*this,x,y,z) {
philpem@5 32428 cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k);
philpem@5 32429 cimg::fwrite(buf.data,dim,nfile);
philpem@5 32430 }
philpem@5 32431 }
philpem@5 32432 if (!file) cimg::fclose(nfile);
philpem@5 32433 return *this;
philpem@5 32434 }
philpem@5 32435
philpem@5 32436 //! Save the image as a RAW file.
philpem@5 32437 const CImg<T>& save_raw(const char *const filename, const bool multiplexed=false) const {
philpem@5 32438 return _save_raw(0,filename,multiplexed);
philpem@5 32439 }
philpem@5 32440
philpem@5 32441 //! Save the image as a RAW file.
philpem@5 32442 const CImg<T>& save_raw(cimg_std::FILE *const file, const bool multiplexed=false) const {
philpem@5 32443 return _save_raw(file,0,multiplexed);
philpem@5 32444 }
philpem@5 32445
philpem@5 32446 //! Save the image as a video sequence file, using FFMPEG library.
philpem@5 32447 const CImg<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 32448 const unsigned int fps=25) const {
philpem@5 32449 if (is_empty())
philpem@5 32450 throw CImgInstanceException("CImg<%s>::save_ffmpeg() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32451 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32452 if (!filename)
philpem@5 32453 throw CImgArgumentException("CImg<%s>::save_ffmpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32454 pixel_type(),width,height,depth,dim,data);
philpem@5 32455 if (!fps)
philpem@5 32456 throw CImgArgumentException("CImg<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
philpem@5 32457 pixel_type(),filename);
philpem@5 32458 #ifndef cimg_use_ffmpeg
philpem@5 32459 return save_ffmpeg_external(filename,first_frame,last_frame);
philpem@5 32460 #else
philpem@5 32461 get_split('z').save_ffmpeg(filename,first_frame,last_frame,fps);
philpem@5 32462 #endif
philpem@5 32463 return *this;
philpem@5 32464 }
philpem@5 32465
philpem@5 32466 //! Save the image as a YUV video sequence file.
philpem@5 32467 const CImg<T>& save_yuv(const char *const filename, const bool rgb2yuv=true) const {
philpem@5 32468 get_split('z').save_yuv(filename,rgb2yuv);
philpem@5 32469 return *this;
philpem@5 32470 }
philpem@5 32471
philpem@5 32472 //! Save the image as a YUV video sequence file.
philpem@5 32473 const CImg<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
philpem@5 32474 get_split('z').save_yuv(file,rgb2yuv);
philpem@5 32475 return *this;
philpem@5 32476 }
philpem@5 32477
philpem@5 32478 // Save OFF files (internal).
philpem@5 32479 template<typename tf, typename tc>
philpem@5 32480 const CImg<T>& _save_off(cimg_std::FILE *const file, const char *const filename,
philpem@5 32481 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces) const {
philpem@5 32482 if (is_empty())
philpem@5 32483 throw CImgInstanceException("CImg<%s>::save_off() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32484 pixel_type(),filename?filename:"(FILE*)",width,height,depth,dim,data);
philpem@5 32485 if (!file && !filename)
philpem@5 32486 throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",
philpem@5 32487 pixel_type());
philpem@5 32488 if (height<3) return get_resize(-100,3,1,1,0)._save_off(file,filename,primitives,colors,invert_faces);
philpem@5 32489 CImgList<tc> _colors;
philpem@5 32490 if (!colors) _colors.insert(primitives.size,CImg<tc>::vector(200,200,200));
philpem@5 32491 const CImgList<tc>& ncolors = colors?colors:_colors;
philpem@5 32492
philpem@5 32493 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
philpem@5 32494 cimg_std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size);
philpem@5 32495 cimg_forX(*this,i) cimg_std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2)));
philpem@5 32496 cimglist_for(primitives,l) {
philpem@5 32497 const unsigned int prim = primitives[l].size();
philpem@5 32498 const bool textured = (prim>4);
philpem@5 32499 const CImg<tc>& color = ncolors[l];
philpem@5 32500 const unsigned int s = textured?color.dimv():color.size();
philpem@5 32501 const float
philpem@5 32502 r = textured?(s>0?(float)(color.get_shared_channel(0).mean()/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f),
philpem@5 32503 g = textured?(s>1?(float)(color.get_shared_channel(1).mean()/255.0f):r) :(s>1?(float)(color(1)/255.0f):r),
philpem@5 32504 b = textured?(s>2?(float)(color.get_shared_channel(2).mean()/255.0f):r) :(s>2?(float)(color(2)/255.0f):r);
philpem@5 32505
philpem@5 32506 switch (prim) {
philpem@5 32507 case 1 :
philpem@5 32508 cimg_std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b);
philpem@5 32509 break;
philpem@5 32510 case 2 : case 6 :
philpem@5 32511 cimg_std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b);
philpem@5 32512 break;
philpem@5 32513 case 3 : case 9 :
philpem@5 32514 if (invert_faces)
philpem@5 32515 cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),r,g,b);
philpem@5 32516 else
philpem@5 32517 cimg_std::fprintf(nfile,"3 %u %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
philpem@5 32518 break;
philpem@5 32519 case 4 : case 12 :
philpem@5 32520 if (invert_faces)
philpem@5 32521 cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
philpem@5 32522 (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b);
philpem@5 32523 else
philpem@5 32524 cimg_std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n",
philpem@5 32525 (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b);
philpem@5 32526 break;
philpem@5 32527 }
philpem@5 32528 }
philpem@5 32529 if (!file) cimg::fclose(nfile);
philpem@5 32530 return *this;
philpem@5 32531 }
philpem@5 32532
philpem@5 32533 //! Save OFF files.
philpem@5 32534 template<typename tf, typename tc>
philpem@5 32535 const CImg<T>& save_off(const char *const filename,
philpem@5 32536 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
philpem@5 32537 return _save_off(0,filename,primitives,colors,invert_faces);
philpem@5 32538 }
philpem@5 32539
philpem@5 32540 //! Save OFF files.
philpem@5 32541 template<typename tf, typename tc>
philpem@5 32542 const CImg<T>& save_off(cimg_std::FILE *const file,
philpem@5 32543 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
philpem@5 32544 return _save_off(file,0,primitives,colors,invert_faces);
philpem@5 32545 }
philpem@5 32546
philpem@5 32547 //! Save the image as a video sequence file, using the external tool 'ffmpeg'.
philpem@5 32548 const CImg<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 32549 const char *const codec="mpeg2video") const {
philpem@5 32550 if (is_empty())
philpem@5 32551 throw CImgInstanceException("CImg<%s>::save_ffmpeg_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32552 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32553 if (!filename)
philpem@5 32554 throw CImgArgumentException("CImg<%s>::save_ffmpeg_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32555 pixel_type(),width,height,depth,dim,data);
philpem@5 32556 get_split('z').save_ffmpeg_external(filename,first_frame,last_frame,codec);
philpem@5 32557 return *this;
philpem@5 32558 }
philpem@5 32559
philpem@5 32560 //! Save the image using GraphicsMagick's gm.
philpem@5 32561 /** Function that saves the image for other file formats that are not natively handled by CImg,
philpem@5 32562 using the tool 'gm' from the GraphicsMagick package.\n
philpem@5 32563 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
philpem@5 32564 the GraphicsMagick package in order to get
philpem@5 32565 this function working properly (see http://www.graphicsmagick.org ).
philpem@5 32566 **/
philpem@5 32567 const CImg<T>& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const {
philpem@5 32568 if (is_empty())
philpem@5 32569 throw CImgInstanceException("CImg<%s>::save_graphicsmagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32570 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32571 if (!filename)
philpem@5 32572 throw CImgArgumentException("CImg<%s>::save_graphicsmagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32573 pixel_type(),width,height,depth,dim,data);
philpem@5 32574 char command[1024],filetmp[512];
philpem@5 32575 cimg_std::FILE *file;
philpem@5 32576 do {
philpem@5 32577 if (dim==1) cimg_std::sprintf(filetmp,"%s%s%s.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 32578 else cimg_std::sprintf(filetmp,"%s%s%s.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 32579 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 32580 } while (file);
philpem@5 32581 save_pnm(filetmp);
philpem@5 32582 cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename);
philpem@5 32583 cimg::system(command);
philpem@5 32584 file = cimg_std::fopen(filename,"rb");
philpem@5 32585 if (!file)
philpem@5 32586 throw CImgIOException("CImg<%s>::save_graphicsmagick_external() : Failed to save image '%s'.\n\n"
philpem@5 32587 "Path of 'gm' : \"%s\"\n"
philpem@5 32588 "Path of temporary filename : \"%s\"\n",
philpem@5 32589 pixel_type(),filename,cimg::graphicsmagick_path(),filetmp);
philpem@5 32590 if (file) cimg::fclose(file);
philpem@5 32591 cimg_std::remove(filetmp);
philpem@5 32592 return *this;
philpem@5 32593 }
philpem@5 32594
philpem@5 32595 //! Save an image as a gzipped file, using external tool 'gzip'.
philpem@5 32596 const CImg<T>& save_gzip_external(const char *const filename) const {
philpem@5 32597 if (!filename)
philpem@5 32598 throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
philpem@5 32599 pixel_type());
philpem@5 32600 char command[1024], filetmp[512], body[512];
philpem@5 32601 const char
philpem@5 32602 *ext = cimg::split_filename(filename,body),
philpem@5 32603 *ext2 = cimg::split_filename(body,0);
philpem@5 32604 cimg_std::FILE *file;
philpem@5 32605 do {
philpem@5 32606 if (!cimg::strcasecmp(ext,"gz")) {
philpem@5 32607 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 32608 cimg::filenamerand(),ext2);
philpem@5 32609 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 32610 cimg::filenamerand());
philpem@5 32611 } else {
philpem@5 32612 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 32613 cimg::filenamerand(),ext);
philpem@5 32614 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 32615 cimg::filenamerand());
philpem@5 32616 }
philpem@5 32617 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 32618 } while (file);
philpem@5 32619 save(filetmp);
philpem@5 32620 cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
philpem@5 32621 cimg::system(command);
philpem@5 32622 file = cimg_std::fopen(filename,"rb");
philpem@5 32623 if (!file)
philpem@5 32624 throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
philpem@5 32625 pixel_type(),filename);
philpem@5 32626 else cimg::fclose(file);
philpem@5 32627 cimg_std::remove(filetmp);
philpem@5 32628 return *this;
philpem@5 32629 }
philpem@5 32630
philpem@5 32631 //! Save the image using ImageMagick's convert.
philpem@5 32632 /** Function that saves the image for other file formats that are not natively handled by CImg,
philpem@5 32633 using the tool 'convert' from the ImageMagick package.\n
philpem@5 32634 This is the case for all compressed image formats (GIF,PNG,JPG,TIF, ...). You need to install
philpem@5 32635 the ImageMagick package in order to get
philpem@5 32636 this function working properly (see http://www.imagemagick.org ).
philpem@5 32637 **/
philpem@5 32638 const CImg<T>& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const {
philpem@5 32639 if (is_empty())
philpem@5 32640 throw CImgInstanceException("CImg<%s>::save_imagemagick_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32641 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32642 if (!filename)
philpem@5 32643 throw CImgArgumentException("CImg<%s>::save_imagemagick_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32644 pixel_type(),width,height,depth,dim,data);
philpem@5 32645 char command[1024], filetmp[512];
philpem@5 32646 cimg_std::FILE *file;
philpem@5 32647 do {
philpem@5 32648 cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand(),dim==1?"pgm":"ppm");
philpem@5 32649 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 32650 } while (file);
philpem@5 32651 save_pnm(filetmp);
philpem@5 32652 cimg_std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename);
philpem@5 32653 cimg::system(command);
philpem@5 32654 file = cimg_std::fopen(filename,"rb");
philpem@5 32655 if (!file)
philpem@5 32656 throw CImgIOException("CImg<%s>::save_imagemagick_external() : Failed to save image '%s'.\n\n"
philpem@5 32657 "Path of 'convert' : \"%s\"\n"
philpem@5 32658 "Path of temporary filename : \"%s\"\n",
philpem@5 32659 pixel_type(),filename,cimg::imagemagick_path(),filetmp);
philpem@5 32660 if (file) cimg::fclose(file);
philpem@5 32661 cimg_std::remove(filetmp);
philpem@5 32662 return *this;
philpem@5 32663 }
philpem@5 32664
philpem@5 32665 //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net )
philpem@5 32666 const CImg<T>& save_medcon_external(const char *const filename) const {
philpem@5 32667 if (is_empty())
philpem@5 32668 throw CImgInstanceException("CImg<%s>::save_medcon_external() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32669 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32670 if (!filename)
philpem@5 32671 throw CImgArgumentException("CImg<%s>::save_medcon_external() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32672 pixel_type(),width,height,depth,dim,data);
philpem@5 32673
philpem@5 32674 char command[1024], filetmp[512], body[512];
philpem@5 32675 cimg_std::FILE *file;
philpem@5 32676 do {
philpem@5 32677 cimg_std::sprintf(filetmp,"%s.hdr",cimg::filenamerand());
philpem@5 32678 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 32679 } while (file);
philpem@5 32680 save_analyze(filetmp);
philpem@5 32681 cimg_std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp);
philpem@5 32682 cimg::system(command);
philpem@5 32683 cimg_std::remove(filetmp);
philpem@5 32684 cimg::split_filename(filetmp,body);
philpem@5 32685 cimg_std::sprintf(filetmp,"%s.img",body);
philpem@5 32686 cimg_std::remove(filetmp);
philpem@5 32687 cimg_std::sprintf(command,"m000-%s",filename);
philpem@5 32688 file = cimg_std::fopen(command,"rb");
philpem@5 32689 if (!file) {
philpem@5 32690 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 32691 throw CImgIOException("CImg<%s>::save_medcon_external() : Failed to save image '%s'.\n\n"
philpem@5 32692 "Path of 'medcon' : \"%s\"\n"
philpem@5 32693 "Path of temporary filename : \"%s\"",
philpem@5 32694 pixel_type(),filename,cimg::medcon_path(),filetmp);
philpem@5 32695 } else cimg::fclose(file);
philpem@5 32696 cimg_std::rename(command,filename);
philpem@5 32697 return *this;
philpem@5 32698 }
philpem@5 32699
philpem@5 32700 // Try to save the image if other extension is provided.
philpem@5 32701 const CImg<T>& save_other(const char *const filename, const unsigned int quality=100) const {
philpem@5 32702 if (is_empty())
philpem@5 32703 throw CImgInstanceException("CImg<%s>::save_other() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.",
philpem@5 32704 pixel_type(),filename?filename:"(null)",width,height,depth,dim,data);
philpem@5 32705 if (!filename)
philpem@5 32706 throw CImgIOException("CImg<%s>::save_other() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).",
philpem@5 32707 pixel_type());
philpem@5 32708 const unsigned int odebug = cimg::exception_mode();
philpem@5 32709 bool is_saved = true;
philpem@5 32710 cimg::exception_mode() = 0;
philpem@5 32711 try { save_magick(filename); }
philpem@5 32712 catch (CImgException&) {
philpem@5 32713 try { save_imagemagick_external(filename,quality); }
philpem@5 32714 catch (CImgException&) {
philpem@5 32715 try { save_graphicsmagick_external(filename,quality); }
philpem@5 32716 catch (CImgException&) {
philpem@5 32717 is_saved = false;
philpem@5 32718 }
philpem@5 32719 }
philpem@5 32720 }
philpem@5 32721 cimg::exception_mode() = odebug;
philpem@5 32722 if (!is_saved)
philpem@5 32723 throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n"
philpem@5 32724 "Check you have either the ImageMagick or GraphicsMagick package installed.",
philpem@5 32725 pixel_type(),filename);
philpem@5 32726 return *this;
philpem@5 32727 }
philpem@5 32728
philpem@5 32729 // Get a 40x38 color logo of a 'danger' item (internal).
philpem@5 32730 static CImg<T> logo40x38() {
philpem@5 32731 static bool first_time = true;
philpem@5 32732 static CImg<T> res(40,38,1,3);
philpem@5 32733 if (first_time) {
philpem@5 32734 const unsigned char *ptrs = cimg::logo40x38;
philpem@5 32735 T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2);
philpem@5 32736 for (unsigned int off = 0; off<res.width*res.height;) {
philpem@5 32737 const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++);
philpem@5 32738 for (unsigned int l=0; l<n; ++off, ++l) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; }
philpem@5 32739 }
philpem@5 32740 first_time = false;
philpem@5 32741 }
philpem@5 32742 return res;
philpem@5 32743 }
philpem@5 32744
philpem@5 32745 };
philpem@5 32746
philpem@5 32747 /*
philpem@5 32748 #-----------------------------------------
philpem@5 32749 #
philpem@5 32750 #
philpem@5 32751 #
philpem@5 32752 # Definition of the CImgList<> structure
philpem@5 32753 #
philpem@5 32754 #
philpem@5 32755 #
philpem@5 32756 #------------------------------------------
philpem@5 32757 */
philpem@5 32758
philpem@5 32759 //! Class representing list of images CImg<T>.
philpem@5 32760 template<typename T>
philpem@5 32761 struct CImgList {
philpem@5 32762
philpem@5 32763 //! Size of the list (number of elements inside).
philpem@5 32764 unsigned int size;
philpem@5 32765
philpem@5 32766 //! Allocation size of the list.
philpem@5 32767 unsigned int allocsize;
philpem@5 32768
philpem@5 32769 //! Pointer to the first list element.
philpem@5 32770 CImg<T> *data;
philpem@5 32771
philpem@5 32772 //! Define a CImgList<T>::iterator.
philpem@5 32773 typedef CImg<T>* iterator;
philpem@5 32774
philpem@5 32775 //! Define a CImgList<T>::const_iterator.
philpem@5 32776 typedef const CImg<T>* const_iterator;
philpem@5 32777
philpem@5 32778 //! Get value type.
philpem@5 32779 typedef T value_type;
philpem@5 32780
philpem@5 32781 // Define common T-dependant types.
philpem@5 32782 typedef typename cimg::superset<T,bool>::type Tbool;
philpem@5 32783 typedef typename cimg::superset<T,unsigned char>::type Tuchar;
philpem@5 32784 typedef typename cimg::superset<T,char>::type Tchar;
philpem@5 32785 typedef typename cimg::superset<T,unsigned short>::type Tushort;
philpem@5 32786 typedef typename cimg::superset<T,short>::type Tshort;
philpem@5 32787 typedef typename cimg::superset<T,unsigned int>::type Tuint;
philpem@5 32788 typedef typename cimg::superset<T,int>::type Tint;
philpem@5 32789 typedef typename cimg::superset<T,unsigned long>::type Tulong;
philpem@5 32790 typedef typename cimg::superset<T,long>::type Tlong;
philpem@5 32791 typedef typename cimg::superset<T,float>::type Tfloat;
philpem@5 32792 typedef typename cimg::superset<T,double>::type Tdouble;
philpem@5 32793 typedef typename cimg::last<T,bool>::type boolT;
philpem@5 32794 typedef typename cimg::last<T,unsigned char>::type ucharT;
philpem@5 32795 typedef typename cimg::last<T,char>::type charT;
philpem@5 32796 typedef typename cimg::last<T,unsigned short>::type ushortT;
philpem@5 32797 typedef typename cimg::last<T,short>::type shortT;
philpem@5 32798 typedef typename cimg::last<T,unsigned int>::type uintT;
philpem@5 32799 typedef typename cimg::last<T,int>::type intT;
philpem@5 32800 typedef typename cimg::last<T,unsigned long>::type ulongT;
philpem@5 32801 typedef typename cimg::last<T,long>::type longT;
philpem@5 32802 typedef typename cimg::last<T,float>::type floatT;
philpem@5 32803 typedef typename cimg::last<T,double>::type doubleT;
philpem@5 32804
philpem@5 32805 //@}
philpem@5 32806 //---------------------------
philpem@5 32807 //
philpem@5 32808 //! \name Plugins
philpem@5 32809 //@{
philpem@5 32810 //---------------------------
philpem@5 32811 #ifdef cimglist_plugin
philpem@5 32812 #include cimglist_plugin
philpem@5 32813 #endif
philpem@5 32814 #ifdef cimglist_plugin1
philpem@5 32815 #include cimglist_plugin1
philpem@5 32816 #endif
philpem@5 32817 #ifdef cimglist_plugin2
philpem@5 32818 #include cimglist_plugin2
philpem@5 32819 #endif
philpem@5 32820 #ifdef cimglist_plugin3
philpem@5 32821 #include cimglist_plugin3
philpem@5 32822 #endif
philpem@5 32823 #ifdef cimglist_plugin4
philpem@5 32824 #include cimglist_plugin4
philpem@5 32825 #endif
philpem@5 32826 #ifdef cimglist_plugin5
philpem@5 32827 #include cimglist_plugin5
philpem@5 32828 #endif
philpem@5 32829 #ifdef cimglist_plugin6
philpem@5 32830 #include cimglist_plugin6
philpem@5 32831 #endif
philpem@5 32832 #ifdef cimglist_plugin7
philpem@5 32833 #include cimglist_plugin7
philpem@5 32834 #endif
philpem@5 32835 #ifdef cimglist_plugin8
philpem@5 32836 #include cimglist_plugin8
philpem@5 32837 #endif
philpem@5 32838 //@}
philpem@5 32839
philpem@5 32840 //------------------------------------------
philpem@5 32841 //
philpem@5 32842 //! \name Constructors - Destructor - Copy
philpem@5 32843 //@{
philpem@5 32844 //------------------------------------------
philpem@5 32845
philpem@5 32846 //! Destructor.
philpem@5 32847 ~CImgList() {
philpem@5 32848 if (data) delete[] data;
philpem@5 32849 }
philpem@5 32850
philpem@5 32851 //! Default constructor.
philpem@5 32852 CImgList():
philpem@5 32853 size(0),allocsize(0),data(0) {}
philpem@5 32854
philpem@5 32855 //! Construct an image list containing n empty images.
philpem@5 32856 explicit CImgList(const unsigned int n):
philpem@5 32857 size(n) {
philpem@5 32858 data = new CImg<T>[allocsize = cimg::max(16UL,cimg::nearest_pow2(n))];
philpem@5 32859 }
philpem@5 32860
philpem@5 32861 //! Default copy constructor.
philpem@5 32862 template<typename t>
philpem@5 32863 CImgList(const CImgList<t>& list):
philpem@5 32864 size(0),allocsize(0),data(0) {
philpem@5 32865 assign(list.size);
philpem@5 32866 cimglist_for(*this,l) data[l].assign(list[l],false);
philpem@5 32867 }
philpem@5 32868
philpem@5 32869 CImgList(const CImgList<T>& list):
philpem@5 32870 size(0),allocsize(0),data(0) {
philpem@5 32871 assign(list.size);
philpem@5 32872 cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
philpem@5 32873 }
philpem@5 32874
philpem@5 32875 //! Advanced copy constructor.
philpem@5 32876 template<typename t>
philpem@5 32877 CImgList(const CImgList<t>& list, const bool shared):
philpem@5 32878 size(0),allocsize(0),data(0) {
philpem@5 32879 assign(list.size);
philpem@5 32880 if (shared)
philpem@5 32881 throw CImgArgumentException("CImgList<%s>::CImgList() : Cannot construct a list instance with shared images from "
philpem@5 32882 "a CImgList<%s> (different pixel types).",
philpem@5 32883 pixel_type(),CImgList<t>::pixel_type());
philpem@5 32884 cimglist_for(*this,l) data[l].assign(list[l],false);
philpem@5 32885 }
philpem@5 32886
philpem@5 32887 CImgList(const CImgList<T>& list, const bool shared):
philpem@5 32888 size(0),allocsize(0),data(0) {
philpem@5 32889 assign(list.size);
philpem@5 32890 cimglist_for(*this,l) data[l].assign(list[l],shared);
philpem@5 32891 }
philpem@5 32892
philpem@5 32893 //! Construct an image list containing n images with specified size.
philpem@5 32894 CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1,
philpem@5 32895 const unsigned int depth=1, const unsigned int dim=1):
philpem@5 32896 size(0),allocsize(0),data(0) {
philpem@5 32897 assign(n);
philpem@5 32898 cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
philpem@5 32899 }
philpem@5 32900
philpem@5 32901 //! Construct an image list containing n images with specified size, filled with specified value.
philpem@5 32902 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 32903 const unsigned int depth, const unsigned int dim, const T val):
philpem@5 32904 size(0),allocsize(0),data(0) {
philpem@5 32905 assign(n);
philpem@5 32906 cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
philpem@5 32907 }
philpem@5 32908
philpem@5 32909 //! Construct an image list containing n images with specified size and specified pixel values (int version).
philpem@5 32910 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 32911 const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...):
philpem@5 32912 size(0),allocsize(0),data(0) {
philpem@5 32913 #define _CImgList_stdarg(t) { \
philpem@5 32914 assign(n,width,height,depth,dim); \
philpem@5 32915 const unsigned int siz = width*height*depth*dim, nsiz = siz*n; \
philpem@5 32916 T *ptrd = data->data; \
philpem@5 32917 va_list ap; \
philpem@5 32918 va_start(ap,val1); \
philpem@5 32919 for (unsigned int l=0, s=0, i=0; i<nsiz; ++i) { \
philpem@5 32920 *(ptrd++) = (T)(i==0?val0:(i==1?val1:va_arg(ap,t))); \
philpem@5 32921 if ((++s)==siz) { ptrd = data[++l].data; s=0; } \
philpem@5 32922 } \
philpem@5 32923 va_end(ap); \
philpem@5 32924 }
philpem@5 32925 _CImgList_stdarg(int);
philpem@5 32926 }
philpem@5 32927
philpem@5 32928 //! Construct an image list containing n images with specified size and specified pixel values (double version).
philpem@5 32929 CImgList(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 32930 const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...):
philpem@5 32931 size(0),allocsize(0),data(0) {
philpem@5 32932 _CImgList_stdarg(double);
philpem@5 32933 }
philpem@5 32934
philpem@5 32935 //! Construct a list containing n copies of the image img.
philpem@5 32936 template<typename t>
philpem@5 32937 CImgList(const unsigned int n, const CImg<t>& img):
philpem@5 32938 size(0),allocsize(0),data(0) {
philpem@5 32939 assign(n);
philpem@5 32940 cimglist_for(*this,l) data[l].assign(img,img.is_shared);
philpem@5 32941 }
philpem@5 32942
philpem@5 32943 //! Construct a list containing n copies of the image img, forcing the shared state.
philpem@5 32944 template<typename t>
philpem@5 32945 CImgList(const unsigned int n, const CImg<t>& img, const bool shared):
philpem@5 32946 size(0),allocsize(0),data(0) {
philpem@5 32947 assign(n);
philpem@5 32948 cimglist_for(*this,l) data[l].assign(img,shared);
philpem@5 32949 }
philpem@5 32950
philpem@5 32951 //! Construct an image list from one image.
philpem@5 32952 template<typename t>
philpem@5 32953 explicit CImgList(const CImg<t>& img):
philpem@5 32954 size(0),allocsize(0),data(0) {
philpem@5 32955 assign(1);
philpem@5 32956 data[0].assign(img,img.is_shared);
philpem@5 32957 }
philpem@5 32958
philpem@5 32959 //! Construct an image list from one image, forcing the shared state.
philpem@5 32960 template<typename t>
philpem@5 32961 explicit CImgList(const CImg<t>& img, const bool shared):
philpem@5 32962 size(0),allocsize(0),data(0) {
philpem@5 32963 assign(1);
philpem@5 32964 data[0].assign(img,shared);
philpem@5 32965 }
philpem@5 32966
philpem@5 32967 //! Construct an image list from two images.
philpem@5 32968 template<typename t1, typename t2>
philpem@5 32969 CImgList(const CImg<t1>& img1, const CImg<t2>& img2):
philpem@5 32970 size(0),allocsize(0),data(0) {
philpem@5 32971 assign(2);
philpem@5 32972 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared);
philpem@5 32973 }
philpem@5 32974
philpem@5 32975 //! Construct an image list from two images, forcing the shared state.
philpem@5 32976 template<typename t1, typename t2>
philpem@5 32977 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared):
philpem@5 32978 size(0),allocsize(0),data(0) {
philpem@5 32979 assign(2);
philpem@5 32980 data[0].assign(img1,shared); data[1].assign(img2,shared);
philpem@5 32981 }
philpem@5 32982
philpem@5 32983 //! Construct an image list from three images.
philpem@5 32984 template<typename t1, typename t2, typename t3>
philpem@5 32985 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3):
philpem@5 32986 size(0),allocsize(0),data(0) {
philpem@5 32987 assign(3);
philpem@5 32988 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared);
philpem@5 32989 }
philpem@5 32990
philpem@5 32991 //! Construct an image list from three images, forcing the shared state.
philpem@5 32992 template<typename t1, typename t2, typename t3>
philpem@5 32993 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared):
philpem@5 32994 size(0),allocsize(0),data(0) {
philpem@5 32995 assign(3);
philpem@5 32996 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
philpem@5 32997 }
philpem@5 32998
philpem@5 32999 //! Construct an image list from four images.
philpem@5 33000 template<typename t1, typename t2, typename t3, typename t4>
philpem@5 33001 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4):
philpem@5 33002 size(0),allocsize(0),data(0) {
philpem@5 33003 assign(4);
philpem@5 33004 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
philpem@5 33005 }
philpem@5 33006
philpem@5 33007 //! Construct an image list from four images, forcing the shared state.
philpem@5 33008 template<typename t1, typename t2, typename t3, typename t4>
philpem@5 33009 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const bool shared):
philpem@5 33010 size(0),allocsize(0),data(0) {
philpem@5 33011 assign(4);
philpem@5 33012 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33013 }
philpem@5 33014
philpem@5 33015 //! Construct an image list from five images.
philpem@5 33016 template<typename t1, typename t2, typename t3, typename t4, typename t5>
philpem@5 33017 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33018 const CImg<t5>& img5):
philpem@5 33019 size(0),allocsize(0),data(0) {
philpem@5 33020 assign(5);
philpem@5 33021 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
philpem@5 33022 data[4].assign(img5,img5.is_shared);
philpem@5 33023 }
philpem@5 33024
philpem@5 33025 //! Construct an image list from five images, forcing the shared state.
philpem@5 33026 template<typename t1, typename t2, typename t3, typename t4, typename t5>
philpem@5 33027 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33028 const CImg<t5>& img5, const bool shared):
philpem@5 33029 size(0),allocsize(0),data(0) {
philpem@5 33030 assign(5);
philpem@5 33031 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33032 data[4].assign(img5,shared);
philpem@5 33033 }
philpem@5 33034
philpem@5 33035 //! Construct an image list from six images.
philpem@5 33036 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
philpem@5 33037 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33038 const CImg<t5>& img5, const CImg<t6>& img6):
philpem@5 33039 size(0),allocsize(0),data(0) {
philpem@5 33040 assign(6);
philpem@5 33041 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
philpem@5 33042 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared);
philpem@5 33043 }
philpem@5 33044
philpem@5 33045 //! Construct an image list from six images, forcing the shared state.
philpem@5 33046 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
philpem@5 33047 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33048 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared):
philpem@5 33049 size(0),allocsize(0),data(0) {
philpem@5 33050 assign(6);
philpem@5 33051 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33052 data[4].assign(img5,shared); data[5].assign(img6,shared);
philpem@5 33053 }
philpem@5 33054
philpem@5 33055 //! Construct an image list from seven images.
philpem@5 33056 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
philpem@5 33057 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33058 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7):
philpem@5 33059 size(0),allocsize(0),data(0) {
philpem@5 33060 assign(7);
philpem@5 33061 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
philpem@5 33062 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared);
philpem@5 33063 }
philpem@5 33064
philpem@5 33065 //! Construct an image list from seven images, forcing the shared state.
philpem@5 33066 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
philpem@5 33067 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33068 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared):
philpem@5 33069 size(0),allocsize(0),data(0) {
philpem@5 33070 assign(7);
philpem@5 33071 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33072 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
philpem@5 33073 }
philpem@5 33074
philpem@5 33075 //! Construct an image list from eight images.
philpem@5 33076 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
philpem@5 33077 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33078 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8):
philpem@5 33079 size(0),allocsize(0),data(0) {
philpem@5 33080 assign(8);
philpem@5 33081 data[0].assign(img1,img1.is_shared); data[1].assign(img2,img2.is_shared); data[2].assign(img3,img3.is_shared); data[3].assign(img4,img4.is_shared);
philpem@5 33082 data[4].assign(img5,img5.is_shared); data[5].assign(img6,img6.is_shared); data[6].assign(img7,img7.is_shared); data[7].assign(img8,img8.is_shared);
philpem@5 33083 }
philpem@5 33084
philpem@5 33085 //! Construct an image list from eight images, forcing the shared state.
philpem@5 33086 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
philpem@5 33087 CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33088 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared):
philpem@5 33089 size(0),allocsize(0),data(0) {
philpem@5 33090 assign(8);
philpem@5 33091 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33092 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
philpem@5 33093 }
philpem@5 33094
philpem@5 33095 //! Construct an image list from a filename.
philpem@5 33096 CImgList(const char *const filename):
philpem@5 33097 size(0),allocsize(0),data(0) {
philpem@5 33098 assign(filename);
philpem@5 33099 }
philpem@5 33100
philpem@5 33101 //! In-place version of the default constructor and default destructor.
philpem@5 33102 CImgList<T>& assign() {
philpem@5 33103 if (data) delete[] data;
philpem@5 33104 size = allocsize = 0;
philpem@5 33105 data = 0;
philpem@5 33106 return *this;
philpem@5 33107 }
philpem@5 33108
philpem@5 33109 //! Equivalent to assign() (STL-compliant name).
philpem@5 33110 CImgList<T>& clear() {
philpem@5 33111 return assign();
philpem@5 33112 }
philpem@5 33113
philpem@5 33114 //! In-place version of the corresponding constructor.
philpem@5 33115 CImgList<T>& assign(const unsigned int n) {
philpem@5 33116 if (n) {
philpem@5 33117 if (allocsize<n || allocsize>(n<<2)) {
philpem@5 33118 if (data) delete[] data;
philpem@5 33119 data = new CImg<T>[allocsize=cimg::max(16UL,cimg::nearest_pow2(n))];
philpem@5 33120 }
philpem@5 33121 size = n;
philpem@5 33122 } else assign();
philpem@5 33123 return *this;
philpem@5 33124 }
philpem@5 33125
philpem@5 33126 //! In-place version of the corresponding constructor.
philpem@5 33127 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height=1,
philpem@5 33128 const unsigned int depth=1, const unsigned int dim=1) {
philpem@5 33129 assign(n);
philpem@5 33130 cimglist_for(*this,l) data[l].assign(width,height,depth,dim);
philpem@5 33131 return *this;
philpem@5 33132 }
philpem@5 33133
philpem@5 33134 //! In-place version of the corresponding constructor.
philpem@5 33135 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 33136 const unsigned int depth, const unsigned int dim, const T val) {
philpem@5 33137 assign(n);
philpem@5 33138 cimglist_for(*this,l) data[l].assign(width,height,depth,dim,val);
philpem@5 33139 return *this;
philpem@5 33140 }
philpem@5 33141
philpem@5 33142 //! In-place version of the corresponding constructor.
philpem@5 33143 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 33144 const unsigned int depth, const unsigned int dim, const int val0, const int val1, ...) {
philpem@5 33145 _CImgList_stdarg(int);
philpem@5 33146 return *this;
philpem@5 33147 }
philpem@5 33148
philpem@5 33149 //! In-place version of the corresponding constructor.
philpem@5 33150 CImgList<T>& assign(const unsigned int n, const unsigned int width, const unsigned int height,
philpem@5 33151 const unsigned int depth, const unsigned int dim, const double val0, const double val1, ...) {
philpem@5 33152 _CImgList_stdarg(double);
philpem@5 33153 return *this;
philpem@5 33154 }
philpem@5 33155
philpem@5 33156 //! In-place version of the copy constructor.
philpem@5 33157 template<typename t>
philpem@5 33158 CImgList<T>& assign(const CImgList<t>& list) {
philpem@5 33159 assign(list.size);
philpem@5 33160 cimglist_for(*this,l) data[l].assign(list[l],list[l].is_shared);
philpem@5 33161 return *this;
philpem@5 33162 }
philpem@5 33163
philpem@5 33164 //! In-place version of the copy constructor.
philpem@5 33165 template<typename t>
philpem@5 33166 CImgList<T>& assign(const CImgList<t>& list, const bool shared) {
philpem@5 33167 assign(list.size);
philpem@5 33168 cimglist_for(*this,l) data[l].assign(list[l],shared);
philpem@5 33169 return *this;
philpem@5 33170 }
philpem@5 33171
philpem@5 33172 //! In-place version of the corresponding constructor.
philpem@5 33173 template<typename t>
philpem@5 33174 CImgList<T>& assign(const unsigned int n, const CImg<t>& img, const bool shared=false) {
philpem@5 33175 assign(n);
philpem@5 33176 cimglist_for(*this,l) data[l].assign(img,shared);
philpem@5 33177 return *this;
philpem@5 33178 }
philpem@5 33179
philpem@5 33180 //! In-place version of the corresponding constructor.
philpem@5 33181 template<typename t>
philpem@5 33182 CImgList<T>& assign(const CImg<t>& img, const bool shared=false) {
philpem@5 33183 assign(1);
philpem@5 33184 data[0].assign(img,shared);
philpem@5 33185 return *this;
philpem@5 33186 }
philpem@5 33187
philpem@5 33188 //! In-place version of the corresponding constructor.
philpem@5 33189 template<typename t1, typename t2>
philpem@5 33190 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false) {
philpem@5 33191 assign(2);
philpem@5 33192 data[0].assign(img1,shared); data[1].assign(img2,shared);
philpem@5 33193 return *this;
philpem@5 33194 }
philpem@5 33195
philpem@5 33196 //! In-place version of the corresponding constructor.
philpem@5 33197 template<typename t1, typename t2, typename t3>
philpem@5 33198 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) {
philpem@5 33199 assign(3);
philpem@5 33200 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared);
philpem@5 33201 return *this;
philpem@5 33202 }
philpem@5 33203
philpem@5 33204 //! In-place version of the corresponding constructor.
philpem@5 33205 template<typename t1, typename t2, typename t3, typename t4>
philpem@5 33206 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33207 const bool shared=false) {
philpem@5 33208 assign(4);
philpem@5 33209 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33210 return *this;
philpem@5 33211 }
philpem@5 33212
philpem@5 33213 //! In-place version of the corresponding constructor.
philpem@5 33214 template<typename t1, typename t2, typename t3, typename t4, typename t5>
philpem@5 33215 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33216 const CImg<t5>& img5, const bool shared=false) {
philpem@5 33217 assign(5);
philpem@5 33218 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33219 data[4].assign(img5,shared);
philpem@5 33220 return *this;
philpem@5 33221 }
philpem@5 33222
philpem@5 33223 //! In-place version of the corresponding constructor.
philpem@5 33224 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6>
philpem@5 33225 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33226 const CImg<t5>& img5, const CImg<t6>& img6, const bool shared=false) {
philpem@5 33227 assign(6);
philpem@5 33228 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33229 data[4].assign(img5,shared); data[5].assign(img6,shared);
philpem@5 33230 return *this;
philpem@5 33231 }
philpem@5 33232
philpem@5 33233 //! In-place version of the corresponding constructor.
philpem@5 33234 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7>
philpem@5 33235 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33236 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) {
philpem@5 33237 assign(7);
philpem@5 33238 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33239 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared);
philpem@5 33240 return *this;
philpem@5 33241 }
philpem@5 33242
philpem@5 33243 //! In-place version of the corresponding constructor.
philpem@5 33244 template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8>
philpem@5 33245 CImgList<T>& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4,
philpem@5 33246 const CImg<t5>& img5, const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) {
philpem@5 33247 assign(8);
philpem@5 33248 data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared);
philpem@5 33249 data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared);
philpem@5 33250 return *this;
philpem@5 33251 }
philpem@5 33252
philpem@5 33253 //! In-place version of the corresponding constructor.
philpem@5 33254 CImgList<T>& assign(const char *const filename) {
philpem@5 33255 return load(filename);
philpem@5 33256 }
philpem@5 33257
philpem@5 33258 //! Transfer the content of the instance image list into another one.
philpem@5 33259 template<typename t>
philpem@5 33260 CImgList<T>& transfer_to(CImgList<t>& list) {
philpem@5 33261 list.assign(*this);
philpem@5 33262 assign();
philpem@5 33263 return list;
philpem@5 33264 }
philpem@5 33265
philpem@5 33266 CImgList<T>& transfer_to(CImgList<T>& list) {
philpem@5 33267 list.assign();
philpem@5 33268 return swap(list);
philpem@5 33269 }
philpem@5 33270
philpem@5 33271 //! Swap all fields of two CImgList instances (use with care !)
philpem@5 33272 CImgList<T>& swap(CImgList<T>& list) {
philpem@5 33273 cimg::swap(size,list.size);
philpem@5 33274 cimg::swap(allocsize,list.allocsize);
philpem@5 33275 cimg::swap(data,list.data);
philpem@5 33276 return list;
philpem@5 33277 }
philpem@5 33278
philpem@5 33279 //! Return a string describing the type of the image pixels in the list (template parameter \p T).
philpem@5 33280 static const char* pixel_type() {
philpem@5 33281 return cimg::type<T>::string();
philpem@5 33282 }
philpem@5 33283
philpem@5 33284 //! Return \p true if list is empty.
philpem@5 33285 bool is_empty() const {
philpem@5 33286 return (!data || !size);
philpem@5 33287 }
philpem@5 33288
philpem@5 33289 //! Return \p true if list is not empty.
philpem@5 33290 operator bool() const {
philpem@5 33291 return !is_empty();
philpem@5 33292 }
philpem@5 33293
philpem@5 33294 //! Return \p true if list if of specified size.
philpem@5 33295 bool is_sameN(const unsigned int n) const {
philpem@5 33296 return (size==n);
philpem@5 33297 }
philpem@5 33298
philpem@5 33299 //! Return \p true if list if of specified size.
philpem@5 33300 template<typename t>
philpem@5 33301 bool is_sameN(const CImgList<t>& list) const {
philpem@5 33302 return (size==list.size);
philpem@5 33303 }
philpem@5 33304
philpem@5 33305 // Define useful dimension check functions.
philpem@5 33306 // (not documented because they are macro-generated).
philpem@5 33307 #define _cimglist_def_is_same1(axis) \
philpem@5 33308 bool is_same##axis(const unsigned int val) const { \
philpem@5 33309 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(val); return res; \
philpem@5 33310 } \
philpem@5 33311 bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \
philpem@5 33312 return is_sameN(n) && is_same##axis(val); \
philpem@5 33313 } \
philpem@5 33314
philpem@5 33315 #define _cimglist_def_is_same2(axis1,axis2) \
philpem@5 33316 bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \
philpem@5 33317 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2(val1,val2); return res; \
philpem@5 33318 } \
philpem@5 33319 bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \
philpem@5 33320 return is_sameN(n) && is_same##axis1##axis2(val1,val2); \
philpem@5 33321 } \
philpem@5 33322
philpem@5 33323 #define _cimglist_def_is_same3(axis1,axis2,axis3) \
philpem@5 33324 bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
philpem@5 33325 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis1##axis2##axis3(val1,val2,val3); return res; \
philpem@5 33326 } \
philpem@5 33327 bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, const unsigned int val2, const unsigned int val3) const { \
philpem@5 33328 return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \
philpem@5 33329 } \
philpem@5 33330
philpem@5 33331 #define _cimglist_def_is_same(axis) \
philpem@5 33332 template<typename t> bool is_same##axis(const CImg<t>& img) const { \
philpem@5 33333 bool res = true; for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_same##axis(img); return res; \
philpem@5 33334 } \
philpem@5 33335 template<typename t> bool is_same##axis(const CImgList<t>& list) const { \
philpem@5 33336 const unsigned int lmin = cimg::min(size,list.size); \
philpem@5 33337 bool res = true; for (unsigned int l = 0; l<lmin && res; ++l) res = data[l].is_same##axis(list[l]); return res; \
philpem@5 33338 } \
philpem@5 33339 template<typename t> bool is_sameN##axis(const unsigned int n, const CImg<t>& img) const { \
philpem@5 33340 return (is_sameN(n) && is_same##axis(img)); \
philpem@5 33341 } \
philpem@5 33342 template<typename t> bool is_sameN##axis(const CImgList<t>& list) const { \
philpem@5 33343 return (is_sameN(list) && is_same##axis(list)); \
philpem@5 33344 }
philpem@5 33345
philpem@5 33346 _cimglist_def_is_same(XY)
philpem@5 33347 _cimglist_def_is_same(XZ)
philpem@5 33348 _cimglist_def_is_same(XV)
philpem@5 33349 _cimglist_def_is_same(YZ)
philpem@5 33350 _cimglist_def_is_same(YV)
philpem@5 33351 _cimglist_def_is_same(XYZ)
philpem@5 33352 _cimglist_def_is_same(XYV)
philpem@5 33353 _cimglist_def_is_same(YZV)
philpem@5 33354 _cimglist_def_is_same(XYZV)
philpem@5 33355 _cimglist_def_is_same1(X)
philpem@5 33356 _cimglist_def_is_same1(Y)
philpem@5 33357 _cimglist_def_is_same1(Z)
philpem@5 33358 _cimglist_def_is_same1(V)
philpem@5 33359 _cimglist_def_is_same2(X,Y)
philpem@5 33360 _cimglist_def_is_same2(X,Z)
philpem@5 33361 _cimglist_def_is_same2(X,V)
philpem@5 33362 _cimglist_def_is_same2(Y,Z)
philpem@5 33363 _cimglist_def_is_same2(Y,V)
philpem@5 33364 _cimglist_def_is_same2(Z,V)
philpem@5 33365 _cimglist_def_is_same3(X,Y,Z)
philpem@5 33366 _cimglist_def_is_same3(X,Y,V)
philpem@5 33367 _cimglist_def_is_same3(X,Z,V)
philpem@5 33368 _cimglist_def_is_same3(Y,Z,V)
philpem@5 33369
philpem@5 33370 bool is_sameXYZV(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
philpem@5 33371 bool res = true;
philpem@5 33372 for (unsigned int l = 0; l<size && res; ++l) res = data[l].is_sameXYZV(dx,dy,dz,dv);
philpem@5 33373 return res;
philpem@5 33374 }
philpem@5 33375
philpem@5 33376 bool is_sameNXYZV(const unsigned int n, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) const {
philpem@5 33377 return is_sameN(n) && is_sameXYZV(dx,dy,dz,dv);
philpem@5 33378 }
philpem@5 33379
philpem@5 33380 //! Return \c true if the list contains the pixel (n,x,y,z,v).
philpem@5 33381 bool containsNXYZV(const int n, const int x=0, const int y=0, const int z=0, const int v=0) const {
philpem@5 33382 if (is_empty()) return false;
philpem@5 33383 return n>=0 && n<(int)size && x>=0 && x<data[n].dimx() && y>=0 && y<data[n].dimy() && z>=0 && z<data[n].dimz() && v>=0 && v<data[n].dimv();
philpem@5 33384 }
philpem@5 33385
philpem@5 33386 //! Return \c true if the list contains the image (n).
philpem@5 33387 bool containsN(const int n) const {
philpem@5 33388 if (is_empty()) return false;
philpem@5 33389 return n>=0 && n<(int)size;
philpem@5 33390 }
philpem@5 33391
philpem@5 33392 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z,v).
philpem@5 33393 template<typename t>
philpem@5 33394 bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& v) const {
philpem@5 33395 if (is_empty()) return false;
philpem@5 33396 cimglist_for(*this,l) if (data[l].contains(pixel,x,y,z,v)) { n = (t)l; return true; }
philpem@5 33397 return false;
philpem@5 33398 }
philpem@5 33399
philpem@5 33400 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y,z).
philpem@5 33401 template<typename t>
philpem@5 33402 bool contains(const T& pixel, t& n, t& x, t&y, t& z) const {
philpem@5 33403 t v;
philpem@5 33404 return contains(pixel,n,x,y,z,v);
philpem@5 33405 }
philpem@5 33406
philpem@5 33407 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x,y).
philpem@5 33408 template<typename t>
philpem@5 33409 bool contains(const T& pixel, t& n, t& x, t&y) const {
philpem@5 33410 t z,v;
philpem@5 33411 return contains(pixel,n,x,y,z,v);
philpem@5 33412 }
philpem@5 33413
philpem@5 33414 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n,x).
philpem@5 33415 template<typename t>
philpem@5 33416 bool contains(const T& pixel, t& n, t& x) const {
philpem@5 33417 t y,z,v;
philpem@5 33418 return contains(pixel,n,x,y,z,v);
philpem@5 33419 }
philpem@5 33420
philpem@5 33421 //! Return \c true if one of the image list contains the specified referenced value. If true, set coordinates (n).
philpem@5 33422 template<typename t>
philpem@5 33423 bool contains(const T& pixel, t& n) const {
philpem@5 33424 t x,y,z,v;
philpem@5 33425 return contains(pixel,n,x,y,z,v);
philpem@5 33426 }
philpem@5 33427
philpem@5 33428 //! Return \c true if one of the image list contains the specified referenced value.
philpem@5 33429 bool contains(const T& pixel) const {
philpem@5 33430 unsigned int n,x,y,z,v;
philpem@5 33431 return contains(pixel,n,x,y,z,v);
philpem@5 33432 }
philpem@5 33433
philpem@5 33434 //! Return \c true if the list contains the image 'img'. If true, returns the position (n) of the image in the list.
philpem@5 33435 template<typename t>
philpem@5 33436 bool contains(const CImg<T>& img, t& n) const {
philpem@5 33437 if (is_empty()) return false;
philpem@5 33438 const CImg<T> *const ptr = &img;
philpem@5 33439 cimglist_for(*this,i) if (data+i==ptr) { n = (t)i; return true; }
philpem@5 33440 return false;
philpem@5 33441 }
philpem@5 33442
philpem@5 33443 //! Return \c true if the list contains the image img.
philpem@5 33444 bool contains(const CImg<T>& img) const {
philpem@5 33445 unsigned int n;
philpem@5 33446 return contains(img,n);
philpem@5 33447 }
philpem@5 33448
philpem@5 33449 //@}
philpem@5 33450 //------------------------------
philpem@5 33451 //
philpem@5 33452 //! \name Arithmetics Operators
philpem@5 33453 //@{
philpem@5 33454 //------------------------------
philpem@5 33455
philpem@5 33456 //! Assignment operator
philpem@5 33457 template<typename t>
philpem@5 33458 CImgList<T>& operator=(const CImgList<t>& list) {
philpem@5 33459 return assign(list);
philpem@5 33460 }
philpem@5 33461
philpem@5 33462 CImgList<T>& operator=(const CImgList<T>& list) {
philpem@5 33463 return assign(list);
philpem@5 33464 }
philpem@5 33465
philpem@5 33466 //! Assignment operator.
philpem@5 33467 template<typename t>
philpem@5 33468 CImgList<T>& operator=(const CImg<t>& img) {
philpem@5 33469 cimglist_for(*this,l) data[l] = img;
philpem@5 33470 return *this;
philpem@5 33471 }
philpem@5 33472
philpem@5 33473 //! Assignment operator.
philpem@5 33474 CImgList<T>& operator=(const T val) {
philpem@5 33475 cimglist_for(*this,l) data[l].fill(val);
philpem@5 33476 return *this;
philpem@5 33477 }
philpem@5 33478
philpem@5 33479 //! Operator+.
philpem@5 33480 CImgList<T> operator+() const {
philpem@5 33481 return CImgList<T>(*this);
philpem@5 33482 }
philpem@5 33483
philpem@5 33484 //! Operator+=.
philpem@5 33485 #ifdef cimg_use_visualcpp6
philpem@5 33486 CImgList<T>& operator+=(const T val)
philpem@5 33487 #else
philpem@5 33488 template<typename t>
philpem@5 33489 CImgList<T>& operator+=(const t val)
philpem@5 33490 #endif
philpem@5 33491 {
philpem@5 33492 cimglist_for(*this,l) (*this)[l]+=val;
philpem@5 33493 return *this;
philpem@5 33494 }
philpem@5 33495
philpem@5 33496 //! Operator+=.
philpem@5 33497 template<typename t>
philpem@5 33498 CImgList<T>& operator+=(const CImgList<t>& list) {
philpem@5 33499 const unsigned int sizemax = cimg::min(size,list.size);
philpem@5 33500 for (unsigned int l=0; l<sizemax; ++l) (*this)[l]+=list[l];
philpem@5 33501 return *this;
philpem@5 33502 }
philpem@5 33503
philpem@5 33504 //! Operator++ (prefix).
philpem@5 33505 CImgList<T>& operator++() {
philpem@5 33506 cimglist_for(*this,l) ++(*this)[l];
philpem@5 33507 return *this;
philpem@5 33508 }
philpem@5 33509
philpem@5 33510 //! Operator++ (postfix).
philpem@5 33511 CImgList<T> operator++(int) {
philpem@5 33512 CImgList<T> copy(*this);
philpem@5 33513 ++*this;
philpem@5 33514 return copy;
philpem@5 33515 }
philpem@5 33516
philpem@5 33517 //! Operator-.
philpem@5 33518 CImgList<T> operator-() const {
philpem@5 33519 CImgList<T> res(size);
philpem@5 33520 cimglist_for(res,l) res[l].assign(-data[l]);
philpem@5 33521 return res;
philpem@5 33522 }
philpem@5 33523
philpem@5 33524 //! Operator-=.
philpem@5 33525 #ifdef cimg_use_visualcpp6
philpem@5 33526 CImgList<T>& operator-=(const T val)
philpem@5 33527 #else
philpem@5 33528 template<typename t>
philpem@5 33529 CImgList<T>& operator-=(const t val)
philpem@5 33530 #endif
philpem@5 33531 {
philpem@5 33532 cimglist_for(*this,l) (*this)[l]-=val;
philpem@5 33533 return *this;
philpem@5 33534 }
philpem@5 33535
philpem@5 33536 //! Operator-=.
philpem@5 33537 template<typename t>
philpem@5 33538 CImgList<T>& operator-=(const CImgList<t>& list) {
philpem@5 33539 const unsigned int sizemax = min(size,list.size);
philpem@5 33540 for (unsigned int l=0; l<sizemax; ++l) (*this)[l]-=list[l];
philpem@5 33541 return *this;
philpem@5 33542 }
philpem@5 33543
philpem@5 33544 //! Operator-- (prefix).
philpem@5 33545 CImgList<T>& operator--() {
philpem@5 33546 cimglist_for(*this,l) --(*this)[l];
philpem@5 33547 return *this;
philpem@5 33548 }
philpem@5 33549
philpem@5 33550 //! Operator-- (postfix).
philpem@5 33551 CImgList<T> operator--(int) {
philpem@5 33552 CImgList<T> copy(*this);
philpem@5 33553 --*this;
philpem@5 33554 return copy;
philpem@5 33555 }
philpem@5 33556
philpem@5 33557 //! Operator*=.
philpem@5 33558 #ifdef cimg_use_visualcpp6
philpem@5 33559 CImgList<T>& operator*=(const double val)
philpem@5 33560 #else
philpem@5 33561 template<typename t>
philpem@5 33562 CImgList<T>& operator*=(const t val)
philpem@5 33563 #endif
philpem@5 33564 {
philpem@5 33565 cimglist_for(*this,l) (*this)[l]*=val;
philpem@5 33566 return *this;
philpem@5 33567 }
philpem@5 33568
philpem@5 33569 //! Operator*=.
philpem@5 33570 template<typename t>
philpem@5 33571 CImgList<T>& operator*=(const CImgList<t>& list) {
philpem@5 33572 const unsigned int N = cimg::min(size,list.size);
philpem@5 33573 for (unsigned int l=0; l<N; ++l) (*this)[l]*=list[l];
philpem@5 33574 return this;
philpem@5 33575 }
philpem@5 33576
philpem@5 33577 //! Operator/=.
philpem@5 33578 #ifdef cimg_use_visualcpp6
philpem@5 33579 CImgList<T>& operator/=(const double val)
philpem@5 33580 #else
philpem@5 33581 template<typename t>
philpem@5 33582 CImgList<T>& operator/=(const t val)
philpem@5 33583 #endif
philpem@5 33584 {
philpem@5 33585 cimglist_for(*this,l) (*this)[l]/=val;
philpem@5 33586 return *this;
philpem@5 33587 }
philpem@5 33588
philpem@5 33589 //! Operator/=.
philpem@5 33590 template<typename t>
philpem@5 33591 CImgList<T>& operator/=(const CImgList<t>& list) {
philpem@5 33592 const unsigned int N = cimg::min(size,list.size);
philpem@5 33593 for (unsigned int l=0; l<N; ++l) (*this)[l]/=list[l];
philpem@5 33594 return this;
philpem@5 33595 }
philpem@5 33596
philpem@5 33597 //! Return a reference to the maximum pixel value of the instance list.
philpem@5 33598 const T& max() const {
philpem@5 33599 if (is_empty())
philpem@5 33600 throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
philpem@5 33601 pixel_type());
philpem@5 33602 const T *ptrmax = data->data;
philpem@5 33603 T max_value = *ptrmax;
philpem@5 33604 cimglist_for(*this,l) {
philpem@5 33605 const CImg<T>& img = data[l];
philpem@5 33606 cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
philpem@5 33607 }
philpem@5 33608 return *ptrmax;
philpem@5 33609 }
philpem@5 33610
philpem@5 33611 //! Return a reference to the maximum pixel value of the instance list.
philpem@5 33612 T& max() {
philpem@5 33613 if (is_empty())
philpem@5 33614 throw CImgInstanceException("CImgList<%s>::max() : Instance image list is empty.",
philpem@5 33615 pixel_type());
philpem@5 33616 T *ptrmax = data->data;
philpem@5 33617 T max_value = *ptrmax;
philpem@5 33618 cimglist_for(*this,l) {
philpem@5 33619 const CImg<T>& img = data[l];
philpem@5 33620 cimg_for(img,ptr,T) if ((*ptr)>max_value) max_value = *(ptrmax=ptr);
philpem@5 33621 }
philpem@5 33622 return *ptrmax;
philpem@5 33623 }
philpem@5 33624
philpem@5 33625 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33626 const T& min() const {
philpem@5 33627 if (is_empty())
philpem@5 33628 throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
philpem@5 33629 pixel_type());
philpem@5 33630 const T *ptrmin = data->data;
philpem@5 33631 T min_value = *ptrmin;
philpem@5 33632 cimglist_for(*this,l) {
philpem@5 33633 const CImg<T>& img = data[l];
philpem@5 33634 cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
philpem@5 33635 }
philpem@5 33636 return *ptrmin;
philpem@5 33637 }
philpem@5 33638
philpem@5 33639 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33640 T& min() {
philpem@5 33641 if (is_empty())
philpem@5 33642 throw CImgInstanceException("CImgList<%s>::min() : Instance image list is empty.",
philpem@5 33643 pixel_type());
philpem@5 33644 T *ptrmin = data->data;
philpem@5 33645 T min_value = *ptrmin;
philpem@5 33646 cimglist_for(*this,l) {
philpem@5 33647 const CImg<T>& img = data[l];
philpem@5 33648 cimg_for(img,ptr,T) if ((*ptr)<min_value) min_value = *(ptrmin=ptr);
philpem@5 33649 }
philpem@5 33650 return *ptrmin;
philpem@5 33651 }
philpem@5 33652
philpem@5 33653 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33654 template<typename t>
philpem@5 33655 const T& minmax(t& max_val) const {
philpem@5 33656 if (is_empty())
philpem@5 33657 throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
philpem@5 33658 pixel_type());
philpem@5 33659 const T *ptrmin = data->data;
philpem@5 33660 T min_value = *ptrmin, max_value = min_value;
philpem@5 33661 cimglist_for(*this,l) {
philpem@5 33662 const CImg<T>& img = data[l];
philpem@5 33663 cimg_for(img,ptr,T) {
philpem@5 33664 const T val = *ptr;
philpem@5 33665 if (val<min_value) { min_value = val; ptrmin = ptr; }
philpem@5 33666 if (val>max_value) max_value = val;
philpem@5 33667 }
philpem@5 33668 }
philpem@5 33669 max_val = (t)max_value;
philpem@5 33670 return *ptrmin;
philpem@5 33671 }
philpem@5 33672
philpem@5 33673 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33674 template<typename t>
philpem@5 33675 T& minmax(t& max_val) {
philpem@5 33676 if (is_empty())
philpem@5 33677 throw CImgInstanceException("CImgList<%s>::minmax() : Instance image list is empty.",
philpem@5 33678 pixel_type());
philpem@5 33679 T *ptrmin = data->data;
philpem@5 33680 T min_value = *ptrmin, max_value = min_value;
philpem@5 33681 cimglist_for(*this,l) {
philpem@5 33682 const CImg<T>& img = data[l];
philpem@5 33683 cimg_for(img,ptr,T) {
philpem@5 33684 const T val = *ptr;
philpem@5 33685 if (val<min_value) { min_value = val; ptrmin = ptr; }
philpem@5 33686 if (val>max_value) max_value = val;
philpem@5 33687 }
philpem@5 33688 }
philpem@5 33689 max_val = (t)max_value;
philpem@5 33690 return *ptrmin;
philpem@5 33691 }
philpem@5 33692
philpem@5 33693 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33694 template<typename t>
philpem@5 33695 const T& maxmin(t& min_val) const {
philpem@5 33696 if (is_empty())
philpem@5 33697 throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
philpem@5 33698 pixel_type());
philpem@5 33699 const T *ptrmax = data->data;
philpem@5 33700 T min_value = *ptrmax, max_value = min_value;
philpem@5 33701 cimglist_for(*this,l) {
philpem@5 33702 const CImg<T>& img = data[l];
philpem@5 33703 cimg_for(img,ptr,T) {
philpem@5 33704 const T val = *ptr;
philpem@5 33705 if (val>max_value) { max_value = val; ptrmax = ptr; }
philpem@5 33706 if (val<min_value) min_value = val;
philpem@5 33707 }
philpem@5 33708 }
philpem@5 33709 min_val = (t)min_value;
philpem@5 33710 return *ptrmax;
philpem@5 33711 }
philpem@5 33712
philpem@5 33713 //! Return a reference to the minimum pixel value of the instance list.
philpem@5 33714 template<typename t>
philpem@5 33715 T& maxmin(t& min_val) {
philpem@5 33716 if (is_empty())
philpem@5 33717 throw CImgInstanceException("CImgList<%s>::maxmin() : Instance image list is empty.",
philpem@5 33718 pixel_type());
philpem@5 33719 T *ptrmax = data->data;
philpem@5 33720 T min_value = *ptrmax, max_value = min_value;
philpem@5 33721 cimglist_for(*this,l) {
philpem@5 33722 const CImg<T>& img = data[l];
philpem@5 33723 cimg_for(img,ptr,T) {
philpem@5 33724 const T val = *ptr;
philpem@5 33725 if (val>max_value) { max_value = val; ptrmax = ptr; }
philpem@5 33726 if (val<min_value) min_value = val;
philpem@5 33727 }
philpem@5 33728 }
philpem@5 33729 min_val = (t)min_value;
philpem@5 33730 return *ptrmax;
philpem@5 33731 }
philpem@5 33732
philpem@5 33733 //! Return the mean pixel value of the instance list.
philpem@5 33734 double mean() const {
philpem@5 33735 if (is_empty())
philpem@5 33736 throw CImgInstanceException("CImgList<%s>::mean() : Instance image list is empty.",
philpem@5 33737 pixel_type());
philpem@5 33738 double val = 0;
philpem@5 33739 unsigned int siz = 0;
philpem@5 33740 cimglist_for(*this,l) {
philpem@5 33741 const CImg<T>& img = data[l];
philpem@5 33742 cimg_for(img,ptr,T) val+=(double)*ptr;
philpem@5 33743 siz+=img.size();
philpem@5 33744 }
philpem@5 33745 return val/siz;
philpem@5 33746 }
philpem@5 33747
philpem@5 33748 //! Return the variance of the instance list.
philpem@5 33749 double variance() {
philpem@5 33750 if (is_empty())
philpem@5 33751 throw CImgInstanceException("CImgList<%s>::variance() : Instance image list is empty.",
philpem@5 33752 pixel_type());
philpem@5 33753 double res = 0;
philpem@5 33754 unsigned int siz = 0;
philpem@5 33755 double S = 0, S2 = 0;
philpem@5 33756 cimglist_for(*this,l) {
philpem@5 33757 const CImg<T>& img = data[l];
philpem@5 33758 cimg_for(img,ptr,T) { const double val = (double)*ptr; S+=val; S2+=val*val; }
philpem@5 33759 siz+=img.size();
philpem@5 33760 }
philpem@5 33761 res = (S2 - S*S/siz)/siz;
philpem@5 33762 return res;
philpem@5 33763 }
philpem@5 33764
philpem@5 33765 //! Compute a list of statistics vectors (min,max,mean,variance,xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax).
philpem@5 33766 CImgList<T>& stats(const unsigned int variance_method=1) {
philpem@5 33767 if (is_empty()) return *this;
philpem@5 33768 cimglist_for(*this,l) data[l].stats(variance_method);
philpem@5 33769 return *this;
philpem@5 33770 }
philpem@5 33771
philpem@5 33772 CImgList<Tfloat> get_stats(const unsigned int variance_method=1) const {
philpem@5 33773 CImgList<Tfloat> res(size);
philpem@5 33774 cimglist_for(*this,l) res[l] = data[l].get_stats(variance_method);
philpem@5 33775 return res;
philpem@5 33776 }
philpem@5 33777
philpem@5 33778 //@}
philpem@5 33779 //-------------------------
philpem@5 33780 //
philpem@5 33781 //! \name List Manipulation
philpem@5 33782 //@{
philpem@5 33783 //-------------------------
philpem@5 33784
philpem@5 33785 //! Return a reference to the i-th element of the image list.
philpem@5 33786 CImg<T>& operator[](const unsigned int pos) {
philpem@5 33787 #if cimg_debug>=3
philpem@5 33788 if (pos>=size) {
philpem@5 33789 cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
philpem@5 33790 pixel_type(),pos,size);
philpem@5 33791 return *data;
philpem@5 33792 }
philpem@5 33793 #endif
philpem@5 33794 return data[pos];
philpem@5 33795 }
philpem@5 33796
philpem@5 33797 const CImg<T>& operator[](const unsigned int pos) const {
philpem@5 33798 #if cimg_debug>=3
philpem@5 33799 if (pos>=size) {
philpem@5 33800 cimg::warn("CImgList<%s>::operator[] : bad list position %u, in a list of %u images",
philpem@5 33801 pixel_type(),pos,size);
philpem@5 33802 return *data;
philpem@5 33803 }
philpem@5 33804 #endif
philpem@5 33805 return data[pos];
philpem@5 33806 }
philpem@5 33807
philpem@5 33808 //! Equivalent to CImgList<T>::operator[]
philpem@5 33809 CImg<T>& operator()(const unsigned int pos) {
philpem@5 33810 return (*this)[pos];
philpem@5 33811 }
philpem@5 33812
philpem@5 33813 const CImg<T>& operator()(const unsigned int pos) const {
philpem@5 33814 return (*this)[pos];
philpem@5 33815 }
philpem@5 33816
philpem@5 33817 //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list
philpem@5 33818 T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
philpem@5 33819 const unsigned int z=0, const unsigned int v=0) {
philpem@5 33820 return (*this)[pos](x,y,z,v);
philpem@5 33821 }
philpem@5 33822 const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0,
philpem@5 33823 const unsigned int z=0, const unsigned int v=0) const {
philpem@5 33824 return (*this)[pos](x,y,z,v);
philpem@5 33825 }
philpem@5 33826
philpem@5 33827 // This function is only here for template tricks.
philpem@5 33828 T _display_object3d_at2(const int i, const int j) const {
philpem@5 33829 return atNXY(i,0,j,0,0,0);
philpem@5 33830 }
philpem@5 33831
philpem@5 33832 //! Read an image in specified position.
philpem@5 33833 CImg<T>& at(const int pos) {
philpem@5 33834 if (is_empty())
philpem@5 33835 throw CImgInstanceException("CImgList<%s>::at() : Instance list is empty.",
philpem@5 33836 pixel_type());
philpem@5 33837 return data[pos<0?0:pos>=(int)size?(int)size-1:pos];
philpem@5 33838 }
philpem@5 33839
philpem@5 33840 //! Read a pixel value with Dirichlet boundary conditions.
philpem@5 33841 T& atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 33842 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZV(x,y,z,v,out_val);
philpem@5 33843 }
philpem@5 33844
philpem@5 33845 T atNXYZV(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 33846 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZV(x,y,z,v,out_val);
philpem@5 33847 }
philpem@5 33848
philpem@5 33849 //! Read a pixel value with Neumann boundary conditions.
philpem@5 33850 T& atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
philpem@5 33851 if (is_empty())
philpem@5 33852 throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
philpem@5 33853 pixel_type());
philpem@5 33854 return _atNXYZV(pos,x,y,z,v);
philpem@5 33855 }
philpem@5 33856
philpem@5 33857 T atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
philpem@5 33858 if (is_empty())
philpem@5 33859 throw CImgInstanceException("CImgList<%s>::atNXYZV() : Instance list is empty.",
philpem@5 33860 pixel_type());
philpem@5 33861 return _atNXYZV(pos,x,y,z,v);
philpem@5 33862 }
philpem@5 33863
philpem@5 33864 T& _atNXYZV(const int pos, const int x, const int y, const int z, const int v) {
philpem@5 33865 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
philpem@5 33866 }
philpem@5 33867
philpem@5 33868 T _atNXYZV(const int pos, const int x, const int y, const int z, const int v) const {
philpem@5 33869 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZV(x,y,z,v);
philpem@5 33870 }
philpem@5 33871
philpem@5 33872 //! Read a pixel value with Dirichlet boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
philpem@5 33873 T& atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 33874 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXYZ(x,y,z,v,out_val);
philpem@5 33875 }
philpem@5 33876
philpem@5 33877 T atNXYZ(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 33878 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXYZ(x,y,z,v,out_val);
philpem@5 33879 }
philpem@5 33880
philpem@5 33881 //! Read a pixel value with Neumann boundary conditions for the four first coordinates (\c pos, \c x,\c y,\c z).
philpem@5 33882 T& atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
philpem@5 33883 if (is_empty())
philpem@5 33884 throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
philpem@5 33885 pixel_type());
philpem@5 33886 return _atNXYZ(pos,x,y,z,v);
philpem@5 33887 }
philpem@5 33888
philpem@5 33889 T atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
philpem@5 33890 if (is_empty())
philpem@5 33891 throw CImgInstanceException("CImgList<%s>::atNXYZ() : Instance list is empty.",
philpem@5 33892 pixel_type());
philpem@5 33893 return _atNXYZ(pos,x,y,z,v);
philpem@5 33894 }
philpem@5 33895
philpem@5 33896 T& _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) {
philpem@5 33897 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
philpem@5 33898 }
philpem@5 33899
philpem@5 33900 T _atNXYZ(const int pos, const int x, const int y, const int z, const int v=0) const {
philpem@5 33901 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXYZ(x,y,z,v);
philpem@5 33902 }
philpem@5 33903
philpem@5 33904 //! Read a pixel value with Dirichlet boundary conditions for the three first coordinates (\c pos, \c x,\c y).
philpem@5 33905 T& atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 33906 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atXY(x,y,z,v,out_val);
philpem@5 33907 }
philpem@5 33908
philpem@5 33909 T atNXY(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 33910 return (pos<0 || pos>=(int)size)?out_val:data[pos].atXY(x,y,z,v,out_val);
philpem@5 33911 }
philpem@5 33912
philpem@5 33913 //! Read a pixel value with Neumann boundary conditions for the three first coordinates (\c pos, \c x,\c y).
philpem@5 33914 T& atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
philpem@5 33915 if (is_empty())
philpem@5 33916 throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
philpem@5 33917 pixel_type());
philpem@5 33918 return _atNXY(pos,x,y,z,v);
philpem@5 33919 }
philpem@5 33920
philpem@5 33921 T atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
philpem@5 33922 if (is_empty())
philpem@5 33923 throw CImgInstanceException("CImgList<%s>::atNXY() : Instance list is empty.",
philpem@5 33924 pixel_type());
philpem@5 33925 return _atNXY(pos,x,y,z,v);
philpem@5 33926 }
philpem@5 33927
philpem@5 33928 T& _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) {
philpem@5 33929 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
philpem@5 33930 }
philpem@5 33931
philpem@5 33932 T _atNXY(const int pos, const int x, const int y, const int z=0, const int v=0) const {
philpem@5 33933 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atXY(x,y,z,v);
philpem@5 33934 }
philpem@5 33935
philpem@5 33936 //! Read a pixel value with Dirichlet boundary conditions for the two first coordinates (\c pos,\c x).
philpem@5 33937 T& atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 33938 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):data[pos].atX(x,y,z,v,out_val);
philpem@5 33939 }
philpem@5 33940
philpem@5 33941 T atNX(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 33942 return (pos<0 || pos>=(int)size)?out_val:data[pos].atX(x,y,z,v,out_val);
philpem@5 33943 }
philpem@5 33944
philpem@5 33945 //! Read a pixel value with Neumann boundary conditions for the two first coordinates (\c pos, \c x).
philpem@5 33946 T& atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
philpem@5 33947 if (is_empty())
philpem@5 33948 throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
philpem@5 33949 pixel_type());
philpem@5 33950 return _atNX(pos,x,y,z,v);
philpem@5 33951 }
philpem@5 33952
philpem@5 33953 T atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 33954 if (is_empty())
philpem@5 33955 throw CImgInstanceException("CImgList<%s>::atNX() : Instance list is empty.",
philpem@5 33956 pixel_type());
philpem@5 33957 return _atNX(pos,x,y,z,v);
philpem@5 33958 }
philpem@5 33959
philpem@5 33960 T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) {
philpem@5 33961 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
philpem@5 33962 }
philpem@5 33963
philpem@5 33964 T _atNX(const int pos, const int x, const int y=0, const int z=0, const int v=0) const {
philpem@5 33965 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)].atX(x,y,z,v);
philpem@5 33966 }
philpem@5 33967
philpem@5 33968 //! Read a pixel value with Dirichlet boundary conditions for the first coordinates (\c pos).
philpem@5 33969 T& atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) {
philpem@5 33970 return (pos<0 || pos>=(int)size)?(cimg::temporary(out_val)=out_val):(*this)(pos,x,y,z,v);
philpem@5 33971 }
philpem@5 33972
philpem@5 33973 T atN(const int pos, const int x, const int y, const int z, const int v, const T out_val) const {
philpem@5 33974 return (pos<0 || pos>=(int)size)?out_val:(*this)(pos,x,y,z,v);
philpem@5 33975 }
philpem@5 33976
philpem@5 33977 //! Read a pixel value with Neumann boundary conditions for the first coordinates (\c pos).
philpem@5 33978 T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
philpem@5 33979 if (is_empty())
philpem@5 33980 throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
philpem@5 33981 pixel_type());
philpem@5 33982 return _atN(pos,x,y,z,v);
philpem@5 33983 }
philpem@5 33984
philpem@5 33985 T atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
philpem@5 33986 if (is_empty())
philpem@5 33987 throw CImgInstanceException("CImgList<%s>::atN() : Instance list is empty.",
philpem@5 33988 pixel_type());
philpem@5 33989 return _atN(pos,x,y,z,v);
philpem@5 33990 }
philpem@5 33991
philpem@5 33992 T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) {
philpem@5 33993 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
philpem@5 33994 }
philpem@5 33995
philpem@5 33996 T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int v=0) const {
philpem@5 33997 return data[pos<0?0:(pos>=(int)size?(int)size-1:pos)](x,y,z,v);
philpem@5 33998 }
philpem@5 33999
philpem@5 34000 //! Returns a reference to the last element.
philpem@5 34001 CImg<T>& back() {
philpem@5 34002 return (*this)(size-1);
philpem@5 34003 }
philpem@5 34004
philpem@5 34005 const CImg<T>& back() const {
philpem@5 34006 return (*this)(size-1);
philpem@5 34007 }
philpem@5 34008
philpem@5 34009 //! Returns a reference to the first element.
philpem@5 34010 CImg<T>& front() {
philpem@5 34011 return *data;
philpem@5 34012 }
philpem@5 34013
philpem@5 34014 const CImg<T>& front() const {
philpem@5 34015 return *data;
philpem@5 34016 }
philpem@5 34017
philpem@5 34018 //! Returns an iterator to the beginning of the vector.
philpem@5 34019 iterator begin() {
philpem@5 34020 return data;
philpem@5 34021 }
philpem@5 34022
philpem@5 34023 const_iterator begin() const {
philpem@5 34024 return data;
philpem@5 34025 }
philpem@5 34026
philpem@5 34027 //! Return a reference to the first image.
philpem@5 34028 const CImg<T>& first() const {
philpem@5 34029 return *data;
philpem@5 34030 }
philpem@5 34031
philpem@5 34032 CImg<T>& first() {
philpem@5 34033 return *data;
philpem@5 34034 }
philpem@5 34035
philpem@5 34036 //! Returns an iterator just past the last element.
philpem@5 34037 iterator end() {
philpem@5 34038 return data + size;
philpem@5 34039 }
philpem@5 34040
philpem@5 34041 const_iterator end() const {
philpem@5 34042 return data + size;
philpem@5 34043 }
philpem@5 34044
philpem@5 34045 //! Return a reference to the last image.
philpem@5 34046 const CImg<T>& last() const {
philpem@5 34047 return data[size - 1];
philpem@5 34048 }
philpem@5 34049
philpem@5 34050 CImg<T>& last() {
philpem@5 34051 return data[size - 1];
philpem@5 34052 }
philpem@5 34053
philpem@5 34054 //! Insert a copy of the image \p img into the current image list, at position \p pos.
philpem@5 34055 template<typename t>
philpem@5 34056 CImgList<T>& insert(const CImg<t>& img, const unsigned int pos, const bool shared) {
philpem@5 34057 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34058 if (npos>size)
philpem@5 34059 throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements",
philpem@5 34060 pixel_type(),npos,size);
philpem@5 34061 if (shared)
philpem@5 34062 throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>",
philpem@5 34063 pixel_type(),img.pixel_type(),pixel_type());
philpem@5 34064 CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
philpem@5 34065 if (!size || !data) {
philpem@5 34066 data = new_data;
philpem@5 34067 *data = img;
philpem@5 34068 } else {
philpem@5 34069 if (new_data) {
philpem@5 34070 if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
philpem@5 34071 if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
philpem@5 34072 cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
philpem@5 34073 delete[] data;
philpem@5 34074 data = new_data;
philpem@5 34075 }
philpem@5 34076 else if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
philpem@5 34077 data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
philpem@5 34078 data[npos] = img;
philpem@5 34079 }
philpem@5 34080 return *this;
philpem@5 34081 }
philpem@5 34082
philpem@5 34083 CImgList<T>& insert(const CImg<T>& img, const unsigned int pos, const bool shared) {
philpem@5 34084 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34085 if (npos>size)
philpem@5 34086 throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements",
philpem@5 34087 pixel_type(),npos,size);
philpem@5 34088 if (&img>=data && &img<data+size) return insert(+img,pos,shared);
philpem@5 34089 CImg<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=16)]:0;
philpem@5 34090 if (!size || !data) {
philpem@5 34091 data = new_data;
philpem@5 34092 if (shared && img) {
philpem@5 34093 data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim;
philpem@5 34094 data->is_shared = true; data->data = img.data;
philpem@5 34095 } else *data = img;
philpem@5 34096 }
philpem@5 34097 else {
philpem@5 34098 if (new_data) {
philpem@5 34099 if (npos) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos);
philpem@5 34100 if (npos!=size-1) cimg_std::memcpy(new_data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
philpem@5 34101 if (shared && img) {
philpem@5 34102 new_data[npos].width = img.width; new_data[npos].height = img.height; new_data[npos].depth = img.depth;
philpem@5 34103 new_data[npos].dim = img.dim; new_data[npos].is_shared = true; new_data[npos].data = img.data;
philpem@5 34104 } else {
philpem@5 34105 new_data[npos].width = new_data[npos].height = new_data[npos].depth = new_data[npos].dim = 0; new_data[npos].data = 0;
philpem@5 34106 new_data[npos] = img;
philpem@5 34107 }
philpem@5 34108 cimg_std::memset(data,0,sizeof(CImg<T>)*(size-1));
philpem@5 34109 delete[] data;
philpem@5 34110 data = new_data;
philpem@5 34111 } else {
philpem@5 34112 if (npos!=size-1) cimg_std::memmove(data+npos+1,data+npos,sizeof(CImg<T>)*(size-1-npos));
philpem@5 34113 if (shared && img) {
philpem@5 34114 data[npos].width = img.width; data[npos].height = img.height; data[npos].depth = img.depth; data[npos].dim = img.dim;
philpem@5 34115 data[npos].is_shared = true; data[npos].data = img.data;
philpem@5 34116 } else {
philpem@5 34117 data[npos].width = data[npos].height = data[npos].depth = data[npos].dim = 0; data[npos].data = 0;
philpem@5 34118 data[npos] = img;
philpem@5 34119 }
philpem@5 34120 }
philpem@5 34121 }
philpem@5 34122 return *this;
philpem@5 34123 }
philpem@5 34124
philpem@5 34125 // The two functions below are necessary due to Visual C++ 6.0 function overloading bugs, when
philpem@5 34126 // default parameters are used in function signatures.
philpem@5 34127 template<typename t>
philpem@5 34128 CImgList<T>& insert(const CImg<t>& img, const unsigned int pos) {
philpem@5 34129 return insert(img,pos,false);
philpem@5 34130 }
philpem@5 34131
philpem@5 34132 //! Insert a copy of the image \p img into the current image list, at position \p pos.
philpem@5 34133 template<typename t>
philpem@5 34134 CImgList<T>& insert(const CImg<t>& img) {
philpem@5 34135 return insert(img,~0U,false);
philpem@5 34136 }
philpem@5 34137
philpem@5 34138 template<typename t>
philpem@5 34139 CImgList<T> get_insert(const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
philpem@5 34140 return (+*this).insert(img,pos,shared);
philpem@5 34141 }
philpem@5 34142
philpem@5 34143 //! Insert n empty images img into the current image list, at position \p pos.
philpem@5 34144 CImgList<T>& insert(const unsigned int n, const unsigned int pos=~0U) {
philpem@5 34145 CImg<T> foo;
philpem@5 34146 if (!n) return *this;
philpem@5 34147 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34148 for (unsigned int i=0; i<n; ++i) insert(foo,npos+i);
philpem@5 34149 return *this;
philpem@5 34150 }
philpem@5 34151
philpem@5 34152 CImgList<T> get_insert(const unsigned int n, const unsigned int pos=~0U) const {
philpem@5 34153 return (+*this).insert(n,pos);
philpem@5 34154 }
philpem@5 34155
philpem@5 34156 //! Insert n copies of the image \p img into the current image list, at position \p pos.
philpem@5 34157 template<typename t>
philpem@5 34158 CImgList<T>& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) {
philpem@5 34159 if (!n) return *this;
philpem@5 34160 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34161 insert(img,npos,shared);
philpem@5 34162 for (unsigned int i=1; i<n; ++i) insert(data[npos],npos+i,shared);
philpem@5 34163 return *this;
philpem@5 34164 }
philpem@5 34165
philpem@5 34166 template<typename t>
philpem@5 34167 CImgList<T> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos=~0U, const bool shared=false) const {
philpem@5 34168 return (+*this).insert(n,img,pos,shared);
philpem@5 34169 }
philpem@5 34170
philpem@5 34171 //! Insert a copy of the image list \p list into the current image list, starting from position \p pos.
philpem@5 34172 template<typename t>
philpem@5 34173 CImgList<T>& insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
philpem@5 34174 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34175 if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos+l,shared);
philpem@5 34176 else insert(CImgList<T>(list),npos,shared);
philpem@5 34177 return *this;
philpem@5 34178 }
philpem@5 34179
philpem@5 34180 template<typename t>
philpem@5 34181 CImgList<T> get_insert(const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
philpem@5 34182 return (+*this).insert(list,pos,shared);
philpem@5 34183 }
philpem@5 34184
philpem@5 34185 //! Insert n copies of the list \p list at position \p pos of the current list.
philpem@5 34186 template<typename t>
philpem@5 34187 CImgList<T>& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) {
philpem@5 34188 if (!n) return *this;
philpem@5 34189 const unsigned int npos = pos==~0U?size:pos;
philpem@5 34190 for (unsigned int i=0; i<n; ++i) insert(list,npos,shared);
philpem@5 34191 return *this;
philpem@5 34192 }
philpem@5 34193
philpem@5 34194 template<typename t>
philpem@5 34195 CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U, const bool shared=false) const {
philpem@5 34196 return (+*this).insert(n,list,pos,shared);
philpem@5 34197 }
philpem@5 34198
philpem@5 34199 //! Insert a copy of the image \p img at the end of the current image list.
philpem@5 34200 template<typename t>
philpem@5 34201 CImgList<T>& operator<<(const CImg<t>& img) {
philpem@5 34202 return insert(img);
philpem@5 34203 }
philpem@5 34204
philpem@5 34205 //! Insert a copy of the image list \p list at the end of the current image list.
philpem@5 34206 template<typename t>
philpem@5 34207 CImgList<T>& operator<<(const CImgList<t>& list) {
philpem@5 34208 return insert(list);
philpem@5 34209 }
philpem@5 34210
philpem@5 34211 //! Return a copy of the current image list, where the image \p img has been inserted at the end.
philpem@5 34212 template<typename t>
philpem@5 34213 CImgList<T>& operator>>(CImg<t>& img) const {
philpem@5 34214 typedef typename cimg::superset<T,t>::type Tt;
philpem@5 34215 return CImgList<Tt>(*this).insert(img);
philpem@5 34216 }
philpem@5 34217
philpem@5 34218 //! Insert a copy of the current image list at the beginning of the image list \p list.
philpem@5 34219 template<typename t>
philpem@5 34220 CImgList<T>& operator>>(CImgList<t>& list) const {
philpem@5 34221 return list.insert(*this,0);
philpem@5 34222 }
philpem@5 34223
philpem@5 34224 //! Remove the images at positions \p pos1 to \p pos2 from the image list.
philpem@5 34225 CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
philpem@5 34226 const unsigned int
philpem@5 34227 npos1 = pos1<pos2?pos1:pos2,
philpem@5 34228 tpos2 = pos1<pos2?pos2:pos1,
philpem@5 34229 npos2 = tpos2<size?tpos2:size-1;
philpem@5 34230 if (npos1>=size)
philpem@5 34231 cimg::warn("CImgList<%s>::remove() : Cannot remove images from a list (%p,%u), at positions %u->%u.",
philpem@5 34232 pixel_type(),data,size,npos1,tpos2);
philpem@5 34233 else {
philpem@5 34234 if (tpos2>=size)
philpem@5 34235 cimg::warn("CImgList<%s>::remove() : Cannot remove all images from a list (%p,%u), at positions %u->%u.",
philpem@5 34236 pixel_type(),data,size,npos1,tpos2);
philpem@5 34237 for (unsigned int k = npos1; k<=npos2; ++k) data[k].assign();
philpem@5 34238 const unsigned int nb = 1 + npos2 - npos1;
philpem@5 34239 if (!(size-=nb)) return assign();
philpem@5 34240 if (size>(allocsize>>2) || allocsize<=8) { // Removing items without reallocation.
philpem@5 34241 if (npos1!=size) cimg_std::memmove(data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
philpem@5 34242 cimg_std::memset(data+size,0,sizeof(CImg<T>)*nb);
philpem@5 34243 } else { // Removing items with reallocation.
philpem@5 34244 allocsize>>=2;
philpem@5 34245 while (allocsize>8 && size<(allocsize>>1)) allocsize>>=1;
philpem@5 34246 CImg<T> *new_data = new CImg<T>[allocsize];
philpem@5 34247 if (npos1) cimg_std::memcpy(new_data,data,sizeof(CImg<T>)*npos1);
philpem@5 34248 if (npos1!=size) cimg_std::memcpy(new_data+npos1,data+npos2+1,sizeof(CImg<T>)*(size-npos1));
philpem@5 34249 if (size!=allocsize) cimg_std::memset(new_data+size,0,sizeof(allocsize-size));
philpem@5 34250 cimg_std::memset(data,0,sizeof(CImg<T>)*(size+nb));
philpem@5 34251 delete[] data;
philpem@5 34252 data = new_data;
philpem@5 34253 }
philpem@5 34254 }
philpem@5 34255 return *this;
philpem@5 34256 }
philpem@5 34257
philpem@5 34258 CImgList<T> get_remove(const unsigned int pos1, const unsigned int pos2) const {
philpem@5 34259 return (+*this).remove(pos1,pos2);
philpem@5 34260 }
philpem@5 34261
philpem@5 34262 //! Remove the image at position \p pos from the image list.
philpem@5 34263 CImgList<T>& remove(const unsigned int pos) {
philpem@5 34264 return remove(pos,pos);
philpem@5 34265 }
philpem@5 34266
philpem@5 34267 CImgList<T> get_remove(const unsigned int pos) const {
philpem@5 34268 return (+*this).remove(pos);
philpem@5 34269 }
philpem@5 34270
philpem@5 34271 //! Remove the last image from the image list.
philpem@5 34272 CImgList<T>& remove() {
philpem@5 34273 if (size) return remove(size-1);
philpem@5 34274 else cimg::warn("CImgList<%s>::remove() : List is empty",
philpem@5 34275 pixel_type());
philpem@5 34276 return *this;
philpem@5 34277 }
philpem@5 34278
philpem@5 34279 CImgList<T> get_remove() const {
philpem@5 34280 return (+*this).remove();
philpem@5 34281 }
philpem@5 34282
philpem@5 34283 //! Reverse list order.
philpem@5 34284 CImgList<T>& reverse() {
philpem@5 34285 for (unsigned int l=0; l<size/2; ++l) (*this)[l].swap((*this)[size-1-l]);
philpem@5 34286 return *this;
philpem@5 34287 }
philpem@5 34288
philpem@5 34289 CImgList<T> get_reverse() const {
philpem@5 34290 return (+*this).reverse();
philpem@5 34291 }
philpem@5 34292
philpem@5 34293 //! Get a sub-list.
philpem@5 34294 CImgList<T>& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) {
philpem@5 34295 return get_crop(i0,i1,shared).transfer_to(*this);
philpem@5 34296 }
philpem@5 34297
philpem@5 34298 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const {
philpem@5 34299 if (i0>i1 || i1>=size)
philpem@5 34300 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
philpem@5 34301 pixel_type(),i0,i1,size,data);
philpem@5 34302 CImgList<T> res(i1-i0+1);
philpem@5 34303 cimglist_for(res,l) res[l].assign((*this)[i0+l],shared);
philpem@5 34304 return res;
philpem@5 34305 }
philpem@5 34306
philpem@5 34307 //! Get sub-images of a sublist.
philpem@5 34308 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
philpem@5 34309 const int x0, const int y0, const int z0, const int v0,
philpem@5 34310 const int x1, const int y1, const int z1, const int v1) {
philpem@5 34311 return get_crop(i0,i1,x0,y0,z0,v0,x1,y1,z1,v1).transfer_to(*this);
philpem@5 34312 }
philpem@5 34313
philpem@5 34314 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
philpem@5 34315 const int x0, const int y0, const int z0, const int v0,
philpem@5 34316 const int x1, const int y1, const int z1, const int v1) const {
philpem@5 34317 if (i0>i1 || i1>=size)
philpem@5 34318 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
philpem@5 34319 pixel_type(),i0,i1,size,data);
philpem@5 34320 CImgList<T> res(i1-i0+1);
philpem@5 34321 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 34322 return res;
philpem@5 34323 }
philpem@5 34324
philpem@5 34325 //! Get sub-images of a sublist.
philpem@5 34326 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
philpem@5 34327 const int x0, const int y0, const int z0,
philpem@5 34328 const int x1, const int y1, const int z1) {
philpem@5 34329 return get_crop(i0,i1,x0,y0,z0,x1,y1,z1).transfer_to(*this);
philpem@5 34330 }
philpem@5 34331
philpem@5 34332 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
philpem@5 34333 const int x0, const int y0, const int z0,
philpem@5 34334 const int x1, const int y1, const int z1) const {
philpem@5 34335 if (i0>i1 || i1>=size)
philpem@5 34336 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
philpem@5 34337 pixel_type(),i0,i1,size,data);
philpem@5 34338 CImgList<T> res(i1-i0+1);
philpem@5 34339 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,z0,x1,y1,z1);
philpem@5 34340 return res;
philpem@5 34341 }
philpem@5 34342
philpem@5 34343 //! Get sub-images of a sublist.
philpem@5 34344 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
philpem@5 34345 const int x0, const int y0,
philpem@5 34346 const int x1, const int y1) {
philpem@5 34347 return get_crop(i0,i1,x0,y0,x1,y1).transfer_to(*this);
philpem@5 34348 }
philpem@5 34349
philpem@5 34350 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
philpem@5 34351 const int x0, const int y0,
philpem@5 34352 const int x1, const int y1) const {
philpem@5 34353 if (i0>i1 || i1>=size)
philpem@5 34354 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
philpem@5 34355 pixel_type(),i0,i1,size,data);
philpem@5 34356 CImgList<T> res(i1-i0+1);
philpem@5 34357 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,y0,x1,y1);
philpem@5 34358 return res;
philpem@5 34359 }
philpem@5 34360
philpem@5 34361 //! Get sub-images of a sublist.
philpem@5 34362 CImgList<T>& crop(const unsigned int i0, const unsigned int i1,
philpem@5 34363 const int x0, const int x1) {
philpem@5 34364 return get_crop(i0,i1,x0,x1).transfer_to(*this);
philpem@5 34365 }
philpem@5 34366
philpem@5 34367 CImgList<T> get_crop(const unsigned int i0, const unsigned int i1,
philpem@5 34368 const int x0, const int x1) const {
philpem@5 34369 if (i0>i1 || i1>=size)
philpem@5 34370 throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)",
philpem@5 34371 pixel_type(),i0,i1,size,data);
philpem@5 34372 CImgList<T> res(i1-i0+1);
philpem@5 34373 cimglist_for(res,l) res[l] = (*this)[i0+l].get_crop(x0,x1);
philpem@5 34374 return res;
philpem@5 34375 }
philpem@5 34376
philpem@5 34377 //! Display an image list into a CImgDisplay.
philpem@5 34378 const CImgList<T>& operator>>(CImgDisplay& disp) const {
philpem@5 34379 return display(disp);
philpem@5 34380 }
philpem@5 34381
philpem@5 34382 //! Insert image \p img at the end of the list.
philpem@5 34383 template<typename t>
philpem@5 34384 CImgList<T>& push_back(const CImg<t>& img) {
philpem@5 34385 return insert(img);
philpem@5 34386 }
philpem@5 34387
philpem@5 34388 //! Insert image \p img at the front of the list.
philpem@5 34389 template<typename t>
philpem@5 34390 CImgList<T>& push_front(const CImg<t>& img) {
philpem@5 34391 return insert(img,0);
philpem@5 34392 }
philpem@5 34393
philpem@5 34394 //! Insert list \p list at the end of the current list.
philpem@5 34395 template<typename t>
philpem@5 34396 CImgList<T>& push_back(const CImgList<t>& list) {
philpem@5 34397 return insert(list);
philpem@5 34398 }
philpem@5 34399
philpem@5 34400 //! Insert list \p list at the front of the current list.
philpem@5 34401 template<typename t>
philpem@5 34402 CImgList<T>& push_front(const CImgList<t>& list) {
philpem@5 34403 return insert(list,0);
philpem@5 34404 }
philpem@5 34405
philpem@5 34406 //! Remove last element of the list.
philpem@5 34407 CImgList<T>& pop_back() {
philpem@5 34408 return remove(size-1);
philpem@5 34409 }
philpem@5 34410
philpem@5 34411 //! Remove first element of the list.
philpem@5 34412 CImgList<T>& pop_front() {
philpem@5 34413 return remove(0);
philpem@5 34414 }
philpem@5 34415
philpem@5 34416 //! Remove the element pointed by iterator \p iter.
philpem@5 34417 CImgList<T>& erase(const iterator iter) {
philpem@5 34418 return remove(iter-data);
philpem@5 34419 }
philpem@5 34420
philpem@5 34421 //@}
philpem@5 34422 //----------------------------
philpem@5 34423 //
philpem@5 34424 //! \name Fourier Transforms
philpem@5 34425 //@{
philpem@5 34426 //----------------------------
philpem@5 34427
philpem@5 34428 //! Compute the Fast Fourier Transform (along the specified axis).
philpem@5 34429 CImgList<T>& FFT(const char axis, const bool invert=false) {
philpem@5 34430 if (is_empty())
philpem@5 34431 throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
philpem@5 34432 pixel_type(),size,data);
philpem@5 34433 if (!data[0])
philpem@5 34434 throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty",
philpem@5 34435 pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data);
philpem@5 34436 if (size>2)
philpem@5 34437 cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
philpem@5 34438 pixel_type(),size,data);
philpem@5 34439 if (size==1) insert(CImg<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0));
philpem@5 34440 CImg<T> &Ir = data[0], &Ii = data[1];
philpem@5 34441 if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim)
philpem@5 34442 throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)"
philpem@5 34443 "have different dimensions",
philpem@5 34444 pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
philpem@5 34445
philpem@5 34446 #ifdef cimg_use_fftw3
philpem@5 34447 fftw_complex *data_in;
philpem@5 34448 fftw_plan data_plan;
philpem@5 34449
philpem@5 34450 switch (cimg::uncase(axis)) {
philpem@5 34451 case 'x' : {
philpem@5 34452 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*Ir.width);
philpem@5 34453 data_plan = fftw_plan_dft_1d(Ir.width,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
philpem@5 34454 cimg_forYZV(Ir,y,z,k) {
philpem@5 34455 T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k);
philpem@5 34456 double *ptrd = (double*)data_in;
philpem@5 34457 cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); }
philpem@5 34458 fftw_execute(data_plan);
philpem@5 34459 const unsigned int fact = Ir.width;
philpem@5 34460 if (invert) { cimg_forX(Ir,x) { *(--ptri) = (T)(*(--ptrd)/fact); *(--ptrr) = (T)(*(--ptrd)/fact); }}
philpem@5 34461 else { cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); }}
philpem@5 34462 }
philpem@5 34463 } break;
philpem@5 34464
philpem@5 34465 case 'y' : {
philpem@5 34466 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height);
philpem@5 34467 data_plan = fftw_plan_dft_1d(Ir.height,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
philpem@5 34468 const unsigned int off = Ir.width;
philpem@5 34469 cimg_forXZV(Ir,x,z,k) {
philpem@5 34470 T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k);
philpem@5 34471 double *ptrd = (double*)data_in;
philpem@5 34472 cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
philpem@5 34473 fftw_execute(data_plan);
philpem@5 34474 const unsigned int fact = Ir.height;
philpem@5 34475 if (invert) { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
philpem@5 34476 else { cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
philpem@5 34477 }
philpem@5 34478 } break;
philpem@5 34479
philpem@5 34480 case 'z' : {
philpem@5 34481 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth);
philpem@5 34482 data_plan = fftw_plan_dft_1d(Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
philpem@5 34483 const unsigned int off = Ir.width*Ir.height;
philpem@5 34484 cimg_forXYV(Ir,x,y,k) {
philpem@5 34485 T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k);
philpem@5 34486 double *ptrd = (double*)data_in;
philpem@5 34487 cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
philpem@5 34488 fftw_execute(data_plan);
philpem@5 34489 const unsigned int fact = Ir.depth;
philpem@5 34490 if (invert) { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
philpem@5 34491 else { cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
philpem@5 34492 }
philpem@5 34493 } break;
philpem@5 34494
philpem@5 34495 case 'v' : {
philpem@5 34496 data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim);
philpem@5 34497 data_plan = fftw_plan_dft_1d(Ir.dim,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
philpem@5 34498 const unsigned int off = Ir.width*Ir.height*Ir.depth;
philpem@5 34499 cimg_forXYZ(Ir,x,y,z) {
philpem@5 34500 T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0);
philpem@5 34501 double *ptrd = (double*)data_in;
philpem@5 34502 cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; }
philpem@5 34503 fftw_execute(data_plan);
philpem@5 34504 const unsigned int fact = Ir.dim;
philpem@5 34505 if (invert) { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)(*(--ptrd)/fact); *ptrr = (T)(*(--ptrd)/fact); }}
philpem@5 34506 else { cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); }}
philpem@5 34507 }
philpem@5 34508 } break;
philpem@5 34509 }
philpem@5 34510
philpem@5 34511 fftw_destroy_plan(data_plan);
philpem@5 34512 fftw_free(data_in);
philpem@5 34513 #else
philpem@5 34514 switch (cimg::uncase(axis)) {
philpem@5 34515 case 'x' : { // Fourier along X
philpem@5 34516 const unsigned int N = Ir.width, N2 = (N>>1);
philpem@5 34517 if (((N-1)&N) && N!=1)
philpem@5 34518 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N",
philpem@5 34519 pixel_type(),N);
philpem@5 34520 for (unsigned int i=0, j=0; i<N2; ++i) {
philpem@5 34521 if (j>i) cimg_forYZV(Ir,y,z,v) { cimg::swap(Ir(i,y,z,v),Ir(j,y,z,v)); cimg::swap(Ii(i,y,z,v),Ii(j,y,z,v));
philpem@5 34522 if (j<N2) {
philpem@5 34523 const unsigned int ri = N-1-i, rj = N-1-j;
philpem@5 34524 cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v));
philpem@5 34525 }}
philpem@5 34526 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
philpem@5 34527 }
philpem@5 34528 for (unsigned int delta=2; delta<=N; delta<<=1) {
philpem@5 34529 const unsigned int delta2 = (delta>>1);
philpem@5 34530 for (unsigned int i=0; i<N; i+=delta) {
philpem@5 34531 float wr = 1, wi = 0;
philpem@5 34532 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
philpem@5 34533 ca = (float)cimg_std::cos(angle),
philpem@5 34534 sa = (float)cimg_std::sin(angle);
philpem@5 34535 for (unsigned int k=0; k<delta2; ++k) {
philpem@5 34536 const unsigned int j = i + k, nj = j + delta2;
philpem@5 34537 cimg_forYZV(Ir,y,z,k) {
philpem@5 34538 T &ir = Ir(j,y,z,k), &ii = Ii(j,y,z,k), &nir = Ir(nj,y,z,k), &nii = Ii(nj,y,z,k);
philpem@5 34539 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
philpem@5 34540 nir = (T)(ir - tmpr);
philpem@5 34541 nii = (T)(ii - tmpi);
philpem@5 34542 ir += (T)tmpr;
philpem@5 34543 ii += (T)tmpi;
philpem@5 34544 }
philpem@5 34545 const float nwr = wr*ca-wi*sa;
philpem@5 34546 wi = wi*ca + wr*sa;
philpem@5 34547 wr = nwr;
philpem@5 34548 }
philpem@5 34549 }
philpem@5 34550 }
philpem@5 34551 if (invert) (*this)/=N;
philpem@5 34552 } break;
philpem@5 34553
philpem@5 34554 case 'y' : { // Fourier along Y
philpem@5 34555 const unsigned int N = Ir.height, N2 = (N>>1);
philpem@5 34556 if (((N-1)&N) && N!=1)
philpem@5 34557 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N",
philpem@5 34558 pixel_type(),N);
philpem@5 34559 for (unsigned int i=0, j=0; i<N2; ++i) {
philpem@5 34560 if (j>i) cimg_forXZV(Ir,x,z,v) { cimg::swap(Ir(x,i,z,v),Ir(x,j,z,v)); cimg::swap(Ii(x,i,z,v),Ii(x,j,z,v));
philpem@5 34561 if (j<N2) {
philpem@5 34562 const unsigned int ri = N-1-i, rj = N-1-j;
philpem@5 34563 cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v));
philpem@5 34564 }}
philpem@5 34565 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
philpem@5 34566 }
philpem@5 34567 for (unsigned int delta=2; delta<=N; delta<<=1) {
philpem@5 34568 const unsigned int delta2 = (delta>>1);
philpem@5 34569 for (unsigned int i=0; i<N; i+=delta) {
philpem@5 34570 float wr = 1, wi = 0;
philpem@5 34571 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
philpem@5 34572 ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
philpem@5 34573 for (unsigned int k=0; k<delta2; ++k) {
philpem@5 34574 const unsigned int j = i + k, nj = j + delta2;
philpem@5 34575 cimg_forXZV(Ir,x,z,k) {
philpem@5 34576 T &ir = Ir(x,j,z,k), &ii = Ii(x,j,z,k), &nir = Ir(x,nj,z,k), &nii = Ii(x,nj,z,k);
philpem@5 34577 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
philpem@5 34578 nir = (T)(ir - tmpr);
philpem@5 34579 nii = (T)(ii - tmpi);
philpem@5 34580 ir += (T)tmpr;
philpem@5 34581 ii += (T)tmpi;
philpem@5 34582 }
philpem@5 34583 const float nwr = wr*ca-wi*sa;
philpem@5 34584 wi = wi*ca + wr*sa;
philpem@5 34585 wr = nwr;
philpem@5 34586 }
philpem@5 34587 }
philpem@5 34588 }
philpem@5 34589 if (invert) (*this)/=N;
philpem@5 34590 } break;
philpem@5 34591
philpem@5 34592 case 'z' : { // Fourier along Z
philpem@5 34593 const unsigned int N = Ir.depth, N2 = (N>>1);
philpem@5 34594 if (((N-1)&N) && N!=1)
philpem@5 34595 throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N",
philpem@5 34596 pixel_type(),N);
philpem@5 34597 for (unsigned int i=0, j=0; i<N2; ++i) {
philpem@5 34598 if (j>i) cimg_forXYV(Ir,x,y,v) { cimg::swap(Ir(x,y,i,v),Ir(x,y,j,v)); cimg::swap(Ii(x,y,i,v),Ii(x,y,j,v));
philpem@5 34599 if (j<N2) {
philpem@5 34600 const unsigned int ri = N-1-i, rj = N-1-j;
philpem@5 34601 cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v));
philpem@5 34602 }}
philpem@5 34603 for (unsigned int m=N, n=N2; (j+=n)>=m; j-=m, m=n, n>>=1) {}
philpem@5 34604 }
philpem@5 34605 for (unsigned int delta=2; delta<=N; delta<<=1) {
philpem@5 34606 const unsigned int delta2 = (delta>>1);
philpem@5 34607 for (unsigned int i=0; i<N; i+=delta) {
philpem@5 34608 float wr = 1, wi = 0;
philpem@5 34609 const float angle = (float)((invert?+1:-1)*2*cimg::valuePI/delta),
philpem@5 34610 ca = (float)cimg_std::cos(angle), sa = (float)cimg_std::sin(angle);
philpem@5 34611 for (unsigned int k=0; k<delta2; ++k) {
philpem@5 34612 const unsigned int j = i + k, nj = j + delta2;
philpem@5 34613 cimg_forXYV(Ir,x,y,k) {
philpem@5 34614 T &ir = Ir(x,y,j,k), &ii = Ii(x,y,j,k), &nir = Ir(x,y,nj,k), &nii = Ii(x,y,nj,k);
philpem@5 34615 const float tmpr = (float)(wr*nir - wi*nii), tmpi = (float)(wr*nii + wi*nir);
philpem@5 34616 nir = (T)(ir - tmpr);
philpem@5 34617 nii = (T)(ii - tmpi);
philpem@5 34618 ir += (T)tmpr;
philpem@5 34619 ii += (T)tmpi;
philpem@5 34620 }
philpem@5 34621 const float nwr = wr*ca-wi*sa;
philpem@5 34622 wi = wi*ca + wr*sa;
philpem@5 34623 wr = nwr;
philpem@5 34624 }
philpem@5 34625 }
philpem@5 34626 }
philpem@5 34627 if (invert) (*this)/=N;
philpem@5 34628 } break;
philpem@5 34629
philpem@5 34630 default :
philpem@5 34631 throw CImgArgumentException("CImgList<%s>::FFT() : Invalid axis '%c', must be 'x','y' or 'z'.");
philpem@5 34632 }
philpem@5 34633 #endif
philpem@5 34634 return *this;
philpem@5 34635 }
philpem@5 34636
philpem@5 34637 CImgList<Tfloat> get_FFT(const char axis, const bool invert=false) const {
philpem@5 34638 return CImgList<Tfloat>(*this).FFT(axis,invert);
philpem@5 34639 }
philpem@5 34640
philpem@5 34641 //! Compute the Fast Fourier Transform of a complex image.
philpem@5 34642 CImgList<T>& FFT(const bool invert=false) {
philpem@5 34643 if (is_empty())
philpem@5 34644 throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",
philpem@5 34645 pixel_type(),size,data);
philpem@5 34646 if (size>2)
philpem@5 34647 cimg::warn("CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",
philpem@5 34648 pixel_type(),size,data);
philpem@5 34649 if (size==1) insert(CImg<T>(data->width,data->height,data->depth,data->dim,0));
philpem@5 34650 CImg<T> &Ir = data[0], &Ii = data[1];
philpem@5 34651 if (Ii.width!=Ir.width || Ii.height!=Ir.height || Ii.depth!=Ir.depth || Ii.dim!=Ir.dim)
philpem@5 34652 throw CImgInstanceException("CImgList<%s>::FFT() : Real (%u,%u,%u,%u,%p) and Imaginary (%u,%u,%u,%u,%p) parts "
philpem@5 34653 "of the instance image have different dimensions",
philpem@5 34654 pixel_type(),Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,
philpem@5 34655 Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data);
philpem@5 34656 #ifdef cimg_use_fftw3
philpem@5 34657 fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth);
philpem@5 34658 fftw_plan data_plan;
philpem@5 34659 const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth;
philpem@5 34660 data_plan = fftw_plan_dft_3d(Ir.width,Ir.height,Ir.depth,data_in,data_in,invert?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE);
philpem@5 34661 cimg_forV(Ir,k) {
philpem@5 34662 T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k);
philpem@5 34663 double *ptrd = (double*)data_in;
philpem@5 34664 for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
philpem@5 34665 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
philpem@5 34666 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
philpem@5 34667 *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri;
philpem@5 34668 }
philpem@5 34669 fftw_execute(data_plan);
philpem@5 34670 ptrd = (double*)data_in;
philpem@5 34671 ptrr = Ir.ptr(0,0,0,k);
philpem@5 34672 ptri = Ii.ptr(0,0,0,k);
philpem@5 34673 if (!invert) for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
philpem@5 34674 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
philpem@5 34675 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
philpem@5 34676 *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++);
philpem@5 34677 }
philpem@5 34678 else for (unsigned int x = 0; x<Ir.width; ++x, ptrr-=wh-1, ptri-=wh-1)
philpem@5 34679 for (unsigned int y = 0; y<Ir.height; ++y, ptrr-=whd-w, ptri-=whd-w)
philpem@5 34680 for (unsigned int z = 0; z<Ir.depth; ++z, ptrr+=wh, ptri+=wh) {
philpem@5 34681 *ptrr = (T)(*(ptrd++)/whd); *ptri = (T)(*(ptrd++)/whd);
philpem@5 34682 }
philpem@5 34683 }
philpem@5 34684 fftw_destroy_plan(data_plan);
philpem@5 34685 fftw_free(data_in);
philpem@5 34686 #else
philpem@5 34687 if (Ir.depth>1) FFT('z',invert);
philpem@5 34688 if (Ir.height>1) FFT('y',invert);
philpem@5 34689 if (Ir.width>1) FFT('x',invert);
philpem@5 34690 #endif
philpem@5 34691 return *this;
philpem@5 34692 }
philpem@5 34693
philpem@5 34694 CImgList<Tfloat> get_FFT(const bool invert=false) const {
philpem@5 34695 return CImgList<Tfloat>(*this).FFT(invert);
philpem@5 34696 }
philpem@5 34697
philpem@5 34698 // Return a list where each image has been split along the specified axis.
philpem@5 34699 CImgList<T>& split(const char axis) {
philpem@5 34700 return get_split(axis).transfer_to(*this);
philpem@5 34701 }
philpem@5 34702
philpem@5 34703 CImgList<T> get_split(const char axis) const {
philpem@5 34704 CImgList<T> res;
philpem@5 34705 cimglist_for(*this,l) {
philpem@5 34706 CImgList<T> tmp = data[l].get_split(axis);
philpem@5 34707 const unsigned int pos = res.size;
philpem@5 34708 res.insert(tmp.size);
philpem@5 34709 cimglist_for(tmp,i) tmp[i].transfer_to(data[pos+i]);
philpem@5 34710 }
philpem@5 34711 return res;
philpem@5 34712 }
philpem@5 34713
philpem@5 34714 //! Return a single image which is the concatenation of all images of the current CImgList instance.
philpem@5 34715 /**
philpem@5 34716 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
philpem@5 34717 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
philpem@5 34718 \return A CImg<T> image corresponding to the concatenation is returned.
philpem@5 34719 **/
philpem@5 34720 CImg<T> get_append(const char axis, const char align='p') const {
philpem@5 34721 if (is_empty()) return CImg<T>();
philpem@5 34722 if (size==1) return +((*this)[0]);
philpem@5 34723 unsigned int dx = 0, dy = 0, dz = 0, dv = 0, pos = 0;
philpem@5 34724 CImg<T> res;
philpem@5 34725 switch (cimg::uncase(axis)) {
philpem@5 34726 case 'x' : {
philpem@5 34727 switch (cimg::uncase(align)) {
philpem@5 34728 case 'x' : { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break;
philpem@5 34729 case 'y' : { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break;
philpem@5 34730 case 'z' : { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
philpem@5 34731 case 'v' : { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
philpem@5 34732 default :
philpem@5 34733 cimglist_for(*this,l) {
philpem@5 34734 const CImg<T>& img = (*this)[l];
philpem@5 34735 dx += img.width;
philpem@5 34736 dy = cimg::max(dy,img.height);
philpem@5 34737 dz = cimg::max(dz,img.depth);
philpem@5 34738 dv = cimg::max(dv,img.dim);
philpem@5 34739 }
philpem@5 34740 }
philpem@5 34741 res.assign(dx,dy,dz,dv,0);
philpem@5 34742 switch (cimg::uncase(align)) {
philpem@5 34743 case 'x' : {
philpem@5 34744 cimglist_for(*this,l) {
philpem@5 34745 res.draw_image(pos,CImg<T>((*this)[l],true).unroll('x'));
philpem@5 34746 pos+=(*this)[l].size();
philpem@5 34747 }
philpem@5 34748 } break;
philpem@5 34749 case 'y' : {
philpem@5 34750 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('y'));
philpem@5 34751 } break;
philpem@5 34752 case 'z' : {
philpem@5 34753 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('z'));
philpem@5 34754 } break;
philpem@5 34755 case 'v' : {
philpem@5 34756 cimglist_for(*this,l) res.draw_image(pos++,CImg<T>((*this)[l],true).unroll('v'));
philpem@5 34757 } break;
philpem@5 34758 case 'p' : {
philpem@5 34759 cimglist_for(*this,l) { res.draw_image(pos,(*this)[l]); pos+=(*this)[l].width; }
philpem@5 34760 } break;
philpem@5 34761 case 'n' : {
philpem@5 34762 cimglist_for(*this,l) {
philpem@5 34763 res.draw_image(pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
philpem@5 34764 pos+=(*this)[l].width;
philpem@5 34765 }
philpem@5 34766 } break;
philpem@5 34767 default : {
philpem@5 34768 cimglist_for(*this,l) {
philpem@5 34769 res.draw_image(pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
philpem@5 34770 pos+=(*this)[l].width;
philpem@5 34771 }
philpem@5 34772 } break;
philpem@5 34773 }
philpem@5 34774 } break;
philpem@5 34775
philpem@5 34776 case 'y' : {
philpem@5 34777 switch (cimg::uncase(align)) {
philpem@5 34778 case 'x' : { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
philpem@5 34779 case 'y' : { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break;
philpem@5 34780 case 'z' : { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
philpem@5 34781 case 'v' : { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
philpem@5 34782 default :
philpem@5 34783 cimglist_for(*this,l) {
philpem@5 34784 const CImg<T>& img = (*this)[l];
philpem@5 34785 dx = cimg::max(dx,img.width);
philpem@5 34786 dy += img.height;
philpem@5 34787 dz = cimg::max(dz,img.depth);
philpem@5 34788 dv = cimg::max(dv,img.dim);
philpem@5 34789 }
philpem@5 34790 }
philpem@5 34791 res.assign(dx,dy,dz,dv,0);
philpem@5 34792 switch (cimg::uncase(align)) {
philpem@5 34793 case 'x' : {
philpem@5 34794 cimglist_for(*this,l) res.draw_image(0,++pos,CImg<T>((*this)[l],true).unroll('x'));
philpem@5 34795 } break;
philpem@5 34796 case 'y' : {
philpem@5 34797 cimglist_for(*this,l) {
philpem@5 34798 res.draw_image(0,pos,CImg<T>((*this)[l],true).unroll('y'));
philpem@5 34799 pos+=(*this)[l].size();
philpem@5 34800 }
philpem@5 34801 } break;
philpem@5 34802 case 'z' : {
philpem@5 34803 cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('z'));
philpem@5 34804 } break;
philpem@5 34805 case 'v' : {
philpem@5 34806 cimglist_for(*this,l) res.draw_image(0,pos++,CImg<T>((*this)[l],true).unroll('v'));
philpem@5 34807 } break;
philpem@5 34808 case 'p' : {
philpem@5 34809 cimglist_for(*this,l) { res.draw_image(0,pos,(*this)[l]); pos+=(*this)[l].height; }
philpem@5 34810 } break;
philpem@5 34811 case 'n' : {
philpem@5 34812 cimglist_for(*this,l) {
philpem@5 34813 res.draw_image(dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim,(*this)[l]);
philpem@5 34814 pos+=(*this)[l].height;
philpem@5 34815 }
philpem@5 34816 } break;
philpem@5 34817 default : {
philpem@5 34818 cimglist_for(*this,l) {
philpem@5 34819 res.draw_image((dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2,(*this)[l]);
philpem@5 34820 pos+=(*this)[l].height;
philpem@5 34821 }
philpem@5 34822 } break;
philpem@5 34823 }
philpem@5 34824 } break;
philpem@5 34825
philpem@5 34826 case 'z' : {
philpem@5 34827 switch (cimg::uncase(align)) {
philpem@5 34828 case 'x' : { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
philpem@5 34829 case 'y' : { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
philpem@5 34830 case 'z' : { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break;
philpem@5 34831 case 'v' : { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
philpem@5 34832 default :
philpem@5 34833 cimglist_for(*this,l) {
philpem@5 34834 const CImg<T>& img = (*this)[l];
philpem@5 34835 dx = cimg::max(dx,img.width);
philpem@5 34836 dy = cimg::max(dy,img.height);
philpem@5 34837 dz += img.depth;
philpem@5 34838 dv = cimg::max(dv,img.dim);
philpem@5 34839 }
philpem@5 34840 }
philpem@5 34841 res.assign(dx,dy,dz,dv,0);
philpem@5 34842 switch (cimg::uncase(align)) {
philpem@5 34843 case 'x' : {
philpem@5 34844 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
philpem@5 34845 } break;
philpem@5 34846 case 'y' : {
philpem@5 34847 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
philpem@5 34848 } break;
philpem@5 34849 case 'z' : {
philpem@5 34850 cimglist_for(*this,l) {
philpem@5 34851 res.draw_image(0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
philpem@5 34852 pos+=(*this)[l].size();
philpem@5 34853 }
philpem@5 34854 } break;
philpem@5 34855 case 'v' : {
philpem@5 34856 cimglist_for(*this,l) res.draw_image(0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
philpem@5 34857 } break;
philpem@5 34858 case 'p' : {
philpem@5 34859 cimglist_for(*this,l) { res.draw_image(0,0,pos,(*this)[l]); pos+=(*this)[l].depth; }
philpem@5 34860 } break;
philpem@5 34861 case 'n' : {
philpem@5 34862 cimglist_for(*this,l) {
philpem@5 34863 res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim,(*this)[l]);
philpem@5 34864 pos+=(*this)[l].depth;
philpem@5 34865 }
philpem@5 34866 } break;
philpem@5 34867 case 'c' : {
philpem@5 34868 cimglist_for(*this,l) {
philpem@5 34869 res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2,(*this)[l]);
philpem@5 34870 pos+=(*this)[l].depth;
philpem@5 34871 }
philpem@5 34872 } break;
philpem@5 34873 }
philpem@5 34874 } break;
philpem@5 34875
philpem@5 34876 case 'v' : {
philpem@5 34877 switch (cimg::uncase(align)) {
philpem@5 34878 case 'x' : { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break;
philpem@5 34879 case 'y' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break;
philpem@5 34880 case 'z' : { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break;
philpem@5 34881 case 'v' : { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break;
philpem@5 34882 default :
philpem@5 34883 cimglist_for(*this,l) {
philpem@5 34884 const CImg<T>& img = (*this)[l];
philpem@5 34885 dx = cimg::max(dx,img.width);
philpem@5 34886 dy = cimg::max(dy,img.height);
philpem@5 34887 dz = cimg::max(dz,img.depth);
philpem@5 34888 dv += img.dim;
philpem@5 34889 }
philpem@5 34890 }
philpem@5 34891 res.assign(dx,dy,dz,dv,0);
philpem@5 34892 switch (cimg::uncase(align)) {
philpem@5 34893 case 'x' : {
philpem@5 34894 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('x'));
philpem@5 34895 } break;
philpem@5 34896 case 'y' : {
philpem@5 34897 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('y'));
philpem@5 34898 } break;
philpem@5 34899 case 'z' : {
philpem@5 34900 cimglist_for(*this,l) res.draw_image(0,0,0,pos++,CImg<T>((*this)[l],true).unroll('v'));
philpem@5 34901 } break;
philpem@5 34902 case 'v' : {
philpem@5 34903 cimglist_for(*this,l) {
philpem@5 34904 res.draw_image(0,0,0,pos,CImg<T>((*this)[l],true).unroll('z'));
philpem@5 34905 pos+=(*this)[l].size();
philpem@5 34906 }
philpem@5 34907 } break;
philpem@5 34908 case 'p' : {
philpem@5 34909 cimglist_for(*this,l) { res.draw_image(0,0,0,pos,(*this)[l]); pos+=(*this)[l].dim; }
philpem@5 34910 } break;
philpem@5 34911 case 'n' : {
philpem@5 34912 cimglist_for(*this,l) {
philpem@5 34913 res.draw_image(dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos,(*this)[l]);
philpem@5 34914 pos+=(*this)[l].dim;
philpem@5 34915 }
philpem@5 34916 } break;
philpem@5 34917 case 'c' : {
philpem@5 34918 cimglist_for(*this,l) {
philpem@5 34919 res.draw_image((dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos,(*this)[l]);
philpem@5 34920 pos+=(*this)[l].dim;
philpem@5 34921 }
philpem@5 34922 } break;
philpem@5 34923 }
philpem@5 34924 } break;
philpem@5 34925 default :
philpem@5 34926 throw CImgArgumentException("CImgList<%s>::get_append() : unknow axis '%c', must be 'x','y','z' or 'v'",
philpem@5 34927 pixel_type(),axis);
philpem@5 34928 }
philpem@5 34929 return res;
philpem@5 34930 }
philpem@5 34931
philpem@5 34932 //! Create an auto-cropped font (along the X axis) from a input font \p font.
philpem@5 34933 CImgList<T>& crop_font() {
philpem@5 34934 return get_crop_font().transfer_to(*this);
philpem@5 34935 }
philpem@5 34936
philpem@5 34937 CImgList<T> get_crop_font() const {
philpem@5 34938 CImgList<T> res;
philpem@5 34939 cimglist_for(*this,l) {
philpem@5 34940 const CImg<T>& letter = (*this)[l];
philpem@5 34941 int xmin = letter.width, xmax = 0;
philpem@5 34942 cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; }
philpem@5 34943 if (xmin>xmax) res.insert(CImg<T>(letter.width,letter.height,1,letter.dim,0));
philpem@5 34944 else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1));
philpem@5 34945 }
philpem@5 34946 res[' '].resize(res['f'].width);
philpem@5 34947 res[' '+256].resize(res['f'].width);
philpem@5 34948 return res;
philpem@5 34949 }
philpem@5 34950
philpem@5 34951 //! Invert primitives orientation of a 3D object.
philpem@5 34952 CImgList<T>& invert_object3d() {
philpem@5 34953 cimglist_for(*this,l) {
philpem@5 34954 CImg<T>& p = data[l];
philpem@5 34955 const unsigned int siz = p.size();
philpem@5 34956 if (siz==2 || siz==3 || siz==6 || siz==9) cimg::swap(p[0],p[1]);
philpem@5 34957 else if (siz==4 || siz==12) cimg::swap(p[0],p[3],p[1],p[2]);
philpem@5 34958 }
philpem@5 34959 return *this;
philpem@5 34960 }
philpem@5 34961
philpem@5 34962 CImgList<T> get_invert_object3d() const {
philpem@5 34963 return (+*this).invert_object3d();
philpem@5 34964 }
philpem@5 34965
philpem@5 34966 //! Return a CImg pre-defined font with desired size.
philpem@5 34967 /**
philpem@5 34968 \param font_height = height of the desired font (can be 11,13,24,38 or 57)
philpem@5 34969 \param fixed_size = tell if the font has a fixed or variable width.
philpem@5 34970 **/
philpem@5 34971 static CImgList<T> font(const unsigned int font_width, const bool variable_size=true) {
philpem@5 34972 if (font_width<=11) {
philpem@5 34973 static CImgList<T> font7x11, nfont7x11;
philpem@5 34974 if (!variable_size && !font7x11) font7x11 = _font(cimg::font7x11,7,11,1,0,false);
philpem@5 34975 if (variable_size && !nfont7x11) nfont7x11 = _font(cimg::font7x11,7,11,1,0,true);
philpem@5 34976 return variable_size?nfont7x11:font7x11;
philpem@5 34977 }
philpem@5 34978 if (font_width<=13) {
philpem@5 34979 static CImgList<T> font10x13, nfont10x13;
philpem@5 34980 if (!variable_size && !font10x13) font10x13 = _font(cimg::font10x13,10,13,1,0,false);
philpem@5 34981 if (variable_size && !nfont10x13) nfont10x13 = _font(cimg::font10x13,10,13,1,0,true);
philpem@5 34982 return variable_size?nfont10x13:font10x13;
philpem@5 34983 }
philpem@5 34984 if (font_width<=17) {
philpem@5 34985 static CImgList<T> font8x17, nfont8x17;
philpem@5 34986 if (!variable_size && !font8x17) font8x17 = _font(cimg::font8x17,8,17,1,0,false);
philpem@5 34987 if (variable_size && !nfont8x17) nfont8x17 = _font(cimg::font8x17,8,17,1,0,true);
philpem@5 34988 return variable_size?nfont8x17:font8x17;
philpem@5 34989 }
philpem@5 34990 if (font_width<=19) {
philpem@5 34991 static CImgList<T> font10x19, nfont10x19;
philpem@5 34992 if (!variable_size && !font10x19) font10x19 = _font(cimg::font10x19,10,19,2,0,false);
philpem@5 34993 if (variable_size && !nfont10x19) nfont10x19 = _font(cimg::font10x19,10,19,2,0,true);
philpem@5 34994 return variable_size?nfont10x19:font10x19;
philpem@5 34995 }
philpem@5 34996 if (font_width<=24) {
philpem@5 34997 static CImgList<T> font12x24, nfont12x24;
philpem@5 34998 if (!variable_size && !font12x24) font12x24 = _font(cimg::font12x24,12,24,2,0,false);
philpem@5 34999 if (variable_size && !nfont12x24) nfont12x24 = _font(cimg::font12x24,12,24,2,0,true);
philpem@5 35000 return variable_size?nfont12x24:font12x24;
philpem@5 35001 }
philpem@5 35002 if (font_width<=32) {
philpem@5 35003 static CImgList<T> font16x32, nfont16x32;
philpem@5 35004 if (!variable_size && !font16x32) font16x32 = _font(cimg::font16x32,16,32,2,0,false);
philpem@5 35005 if (variable_size && !nfont16x32) nfont16x32 = _font(cimg::font16x32,16,32,2,0,true);
philpem@5 35006 return variable_size?nfont16x32:font16x32;
philpem@5 35007 }
philpem@5 35008 if (font_width<=38) {
philpem@5 35009 static CImgList<T> font19x38, nfont19x38;
philpem@5 35010 if (!variable_size && !font19x38) font19x38 = _font(cimg::font19x38,19,38,3,0,false);
philpem@5 35011 if (variable_size && !nfont19x38) nfont19x38 = _font(cimg::font19x38,19,38,3,0,true);
philpem@5 35012 return variable_size?nfont19x38:font19x38;
philpem@5 35013 }
philpem@5 35014 static CImgList<T> font29x57, nfont29x57;
philpem@5 35015 if (!variable_size && !font29x57) font29x57 = _font(cimg::font29x57,29,57,5,0,false);
philpem@5 35016 if (variable_size && !nfont29x57) nfont29x57 = _font(cimg::font29x57,29,57,5,0,true);
philpem@5 35017 return variable_size?nfont29x57:font29x57;
philpem@5 35018 }
philpem@5 35019
philpem@5 35020 static CImgList<T> _font(const unsigned int *const font, const unsigned int w, const unsigned int h,
philpem@5 35021 const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) {
philpem@5 35022 CImgList<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1));
philpem@5 35023 const unsigned int *ptr = font;
philpem@5 35024 unsigned int m = 0, val = 0;
philpem@5 35025 for (unsigned int y=0; y<h; ++y)
philpem@5 35026 for (unsigned int x=0; x<256*w; ++x) {
philpem@5 35027 m>>=1; if (!m) { m = 0x80000000; val = *(ptr++); }
philpem@5 35028 CImg<T>& img = res[x/w], &mask = res[x/w+256];
philpem@5 35029 unsigned int xm = x%w;
philpem@5 35030 img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0);
philpem@5 35031 }
philpem@5 35032 if (variable_size) res.crop_font();
philpem@5 35033 if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0);
philpem@5 35034 return res;
philpem@5 35035 }
philpem@5 35036
philpem@5 35037 //! Display the current CImgList instance in an existing CImgDisplay window (by reference).
philpem@5 35038 /**
philpem@5 35039 This function displays the list images of the current CImgList instance into an existing CImgDisplay window.
philpem@5 35040 Images of the list are concatenated in a single temporarly image for visualization purposes.
philpem@5 35041 The function returns immediately.
philpem@5 35042 \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed.
philpem@5 35043 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
philpem@5 35044 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
philpem@5 35045 \return A reference to the current CImgList instance is returned.
philpem@5 35046 **/
philpem@5 35047 const CImgList<T>& display(CImgDisplay& disp, const char axis='x', const char align='p') const {
philpem@5 35048 get_append(axis,align).display(disp);
philpem@5 35049 return *this;
philpem@5 35050 }
philpem@5 35051
philpem@5 35052 //! Display the current CImgList instance in a new display window.
philpem@5 35053 /**
philpem@5 35054 This function opens a new window with a specific title and displays the list images of the current CImgList instance into it.
philpem@5 35055 Images of the list are concatenated in a single temporarly image for visualization purposes.
philpem@5 35056 The function returns when a key is pressed or the display window is closed by the user.
philpem@5 35057 \param title : specify the title of the opening display window.
philpem@5 35058 \param axis : specify the axis for image concatenation. Can be 'x','y','z' or 'v'.
philpem@5 35059 \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom).
philpem@5 35060 \return A reference to the current CImgList instance is returned.
philpem@5 35061 **/
philpem@5 35062 const CImgList<T>& display(CImgDisplay &disp,
philpem@5 35063 const bool display_info, const char axis='x', const char align='p') const {
philpem@5 35064 if (is_empty())
philpem@5 35065 throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.",
philpem@5 35066 pixel_type(),size,data);
philpem@5 35067 const CImg<T> visu = get_append(axis,align);
philpem@5 35068 if (display_info) print(disp.title);
philpem@5 35069 visu.display(disp,false);
philpem@5 35070 return *this;
philpem@5 35071 }
philpem@5 35072
philpem@5 35073 //! Display the current CImgList instance in a new display window.
philpem@5 35074 const CImgList<T>& display(const char *const title=0,
philpem@5 35075 const bool display_info=true, const char axis='x', const char align='p') const {
philpem@5 35076 const CImg<T> visu = get_append(axis,align);
philpem@5 35077 char ntitle[64] = { 0 };
philpem@5 35078 if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
philpem@5 35079 if (display_info) print(title?title:ntitle);
philpem@5 35080 visu.display(title?title:ntitle,false);
philpem@5 35081 return *this;
philpem@5 35082 }
philpem@5 35083
philpem@5 35084 //@}
philpem@5 35085 //----------------------------------
philpem@5 35086 //
philpem@5 35087 //! \name Input-Output
philpem@5 35088 //@{
philpem@5 35089 //----------------------------------
philpem@5 35090
philpem@5 35091 //! Return a C-string containing the values of all images in the instance list.
philpem@5 35092 CImg<charT> value_string(const char separator=',', const unsigned int max_size=0) const {
philpem@5 35093 if (is_empty()) return CImg<ucharT>(1,1,1,1,0);
philpem@5 35094 CImgList<charT> items;
philpem@5 35095 for (unsigned int l = 0; l<size-1; ++l) {
philpem@5 35096 CImg<charT> item = data[l].value_string(separator,0);
philpem@5 35097 item[item.size()-1] = separator;
philpem@5 35098 items.insert(item);
philpem@5 35099 }
philpem@5 35100 items.insert(data[size-1].value_string(separator,0));
philpem@5 35101 CImg<charT> res = items.get_append('x');
philpem@5 35102 if (max_size) { res.crop(0,max_size); res(max_size) = 0; }
philpem@5 35103 return res;
philpem@5 35104 }
philpem@5 35105
philpem@5 35106 //! Print informations about the list on the standard output.
philpem@5 35107 const CImgList<T>& print(const char* title=0, const bool display_stats=true) const {
philpem@5 35108 unsigned long msiz = 0;
philpem@5 35109 cimglist_for(*this,l) msiz += data[l].size();
philpem@5 35110 msiz*=sizeof(T);
philpem@5 35111 const unsigned int mdisp = msiz<8*1024?0:(msiz<8*1024*1024?1:2);
philpem@5 35112 char ntitle[64] = { 0 };
philpem@5 35113 if (!title) cimg_std::sprintf(ntitle,"CImgList<%s>",pixel_type());
philpem@5 35114 cimg_std::fprintf(cimg_stdout,"%s: this = %p, size = %u [%lu %s], data = (CImg<%s>*)%p.\n",
philpem@5 35115 title?title:ntitle,(void*)this,size,
philpem@5 35116 mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
philpem@5 35117 mdisp==0?"b":(mdisp==1?"Kb":"Mb"),
philpem@5 35118 pixel_type(),(void*)data);
philpem@5 35119 char tmp[16] = { 0 };
philpem@5 35120 cimglist_for(*this,ll) {
philpem@5 35121 cimg_std::sprintf(tmp,"[%d]",ll);
philpem@5 35122 cimg_std::fprintf(cimg_stdout," ");
philpem@5 35123 data[ll].print(tmp,display_stats);
philpem@5 35124 if (ll==3 && size>8) { ll = size-5; cimg_std::fprintf(cimg_stdout," ...\n"); }
philpem@5 35125 }
philpem@5 35126 return *this;
philpem@5 35127 }
philpem@5 35128
philpem@5 35129 //! Load an image list from a file.
philpem@5 35130 CImgList<T>& load(const char *const filename) {
philpem@5 35131 const char *ext = cimg::split_filename(filename);
philpem@5 35132 const unsigned int odebug = cimg::exception_mode();
philpem@5 35133 cimg::exception_mode() = 0;
philpem@5 35134 assign();
philpem@5 35135 try {
philpem@5 35136 #ifdef cimglist_load_plugin
philpem@5 35137 cimglist_load_plugin(filename);
philpem@5 35138 #endif
philpem@5 35139 #ifdef cimglist_load_plugin1
philpem@5 35140 cimglist_load_plugin1(filename);
philpem@5 35141 #endif
philpem@5 35142 #ifdef cimglist_load_plugin2
philpem@5 35143 cimglist_load_plugin2(filename);
philpem@5 35144 #endif
philpem@5 35145 #ifdef cimglist_load_plugin3
philpem@5 35146 cimglist_load_plugin3(filename);
philpem@5 35147 #endif
philpem@5 35148 #ifdef cimglist_load_plugin4
philpem@5 35149 cimglist_load_plugin4(filename);
philpem@5 35150 #endif
philpem@5 35151 #ifdef cimglist_load_plugin5
philpem@5 35152 cimglist_load_plugin5(filename);
philpem@5 35153 #endif
philpem@5 35154 #ifdef cimglist_load_plugin6
philpem@5 35155 cimglist_load_plugin6(filename);
philpem@5 35156 #endif
philpem@5 35157 #ifdef cimglist_load_plugin7
philpem@5 35158 cimglist_load_plugin7(filename);
philpem@5 35159 #endif
philpem@5 35160 #ifdef cimglist_load_plugin8
philpem@5 35161 cimglist_load_plugin8(filename);
philpem@5 35162 #endif
philpem@5 35163 if (!cimg::strcasecmp(ext,"tif") ||
philpem@5 35164 !cimg::strcasecmp(ext,"tiff")) load_tiff(filename);
philpem@5 35165 if (!cimg::strcasecmp(ext,"cimg") ||
philpem@5 35166 !cimg::strcasecmp(ext,"cimgz") ||
philpem@5 35167 !ext[0]) load_cimg(filename);
philpem@5 35168 if (!cimg::strcasecmp(ext,"rec") ||
philpem@5 35169 !cimg::strcasecmp(ext,"par")) load_parrec(filename);
philpem@5 35170 if (!cimg::strcasecmp(ext,"avi") ||
philpem@5 35171 !cimg::strcasecmp(ext,"mov") ||
philpem@5 35172 !cimg::strcasecmp(ext,"asf") ||
philpem@5 35173 !cimg::strcasecmp(ext,"divx") ||
philpem@5 35174 !cimg::strcasecmp(ext,"flv") ||
philpem@5 35175 !cimg::strcasecmp(ext,"mpg") ||
philpem@5 35176 !cimg::strcasecmp(ext,"m1v") ||
philpem@5 35177 !cimg::strcasecmp(ext,"m2v") ||
philpem@5 35178 !cimg::strcasecmp(ext,"m4v") ||
philpem@5 35179 !cimg::strcasecmp(ext,"mjp") ||
philpem@5 35180 !cimg::strcasecmp(ext,"mkv") ||
philpem@5 35181 !cimg::strcasecmp(ext,"mpe") ||
philpem@5 35182 !cimg::strcasecmp(ext,"movie") ||
philpem@5 35183 !cimg::strcasecmp(ext,"ogm") ||
philpem@5 35184 !cimg::strcasecmp(ext,"qt") ||
philpem@5 35185 !cimg::strcasecmp(ext,"rm") ||
philpem@5 35186 !cimg::strcasecmp(ext,"vob") ||
philpem@5 35187 !cimg::strcasecmp(ext,"wmv") ||
philpem@5 35188 !cimg::strcasecmp(ext,"xvid") ||
philpem@5 35189 !cimg::strcasecmp(ext,"mpeg")) load_ffmpeg(filename);
philpem@5 35190 if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename);
philpem@5 35191 if (is_empty()) throw CImgIOException("CImgList<%s>::load()",pixel_type());
philpem@5 35192 } catch (CImgIOException& e) {
philpem@5 35193 if (!cimg::strncasecmp(e.message,"cimg::fopen()",13)) {
philpem@5 35194 cimg::exception_mode() = odebug;
philpem@5 35195 throw CImgIOException("CImgList<%s>::load() : File '%s' cannot be opened.",pixel_type(),filename);
philpem@5 35196 } else try {
philpem@5 35197 assign(1);
philpem@5 35198 data->load(filename);
philpem@5 35199 } catch (CImgException&) {
philpem@5 35200 assign();
philpem@5 35201 }
philpem@5 35202 }
philpem@5 35203 cimg::exception_mode() = odebug;
philpem@5 35204 if (is_empty())
philpem@5 35205 throw CImgIOException("CImgList<%s>::load() : File '%s', format not recognized.",pixel_type(),filename);
philpem@5 35206 return *this;
philpem@5 35207 }
philpem@5 35208
philpem@5 35209 static CImgList<T> get_load(const char *const filename) {
philpem@5 35210 return CImgList<T>().load(filename);
philpem@5 35211 }
philpem@5 35212
philpem@5 35213 //! Load an image list from a .cimg file.
philpem@5 35214 CImgList<T>& load_cimg(const char *const filename) {
philpem@5 35215 return _load_cimg(0,filename);
philpem@5 35216 }
philpem@5 35217
philpem@5 35218 static CImgList<T> get_load_cimg(const char *const filename) {
philpem@5 35219 return CImgList<T>().load_cimg(filename);
philpem@5 35220 }
philpem@5 35221
philpem@5 35222 //! Load an image list from a .cimg file.
philpem@5 35223 CImgList<T>& load_cimg(cimg_std::FILE *const file) {
philpem@5 35224 return _load_cimg(file,0);
philpem@5 35225 }
philpem@5 35226
philpem@5 35227 static CImgList<T> get_load_cimg(cimg_std::FILE *const file) {
philpem@5 35228 return CImgList<T>().load_cimg(file);
philpem@5 35229 }
philpem@5 35230
philpem@5 35231 CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename) {
philpem@5 35232 #ifdef cimg_use_zlib
philpem@5 35233 #define _cimgz_load_cimg_case(Tss) { \
philpem@5 35234 Bytef *const cbuf = new Bytef[csiz]; \
philpem@5 35235 cimg::fread(cbuf,csiz,nfile); \
philpem@5 35236 raw.assign(W,H,D,V); \
philpem@5 35237 unsigned long destlen = raw.size()*sizeof(T); \
philpem@5 35238 uncompress((Bytef*)raw.data,&destlen,cbuf,csiz); \
philpem@5 35239 delete[] cbuf; \
philpem@5 35240 const Tss *ptrs = raw.data; \
philpem@5 35241 for (unsigned int off = raw.size(); off; --off) *(ptrd++) = (T)*(ptrs++); \
philpem@5 35242 }
philpem@5 35243 #else
philpem@5 35244 #define _cimgz_load_cimg_case(Tss) \
philpem@5 35245 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s' contains compressed data, zlib must be used",\
philpem@5 35246 pixel_type(),filename?filename:"(FILE*)");
philpem@5 35247 #endif
philpem@5 35248
philpem@5 35249 #define _cimg_load_cimg_case(Ts,Tss) \
philpem@5 35250 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
philpem@5 35251 for (unsigned int l = 0; l<N; ++l) { \
philpem@5 35252 j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
philpem@5 35253 W = H = D = V = 0; csiz = 0; \
philpem@5 35254 if ((err = cimg_std::sscanf(tmp,"%u %u %u %u #%u",&W,&H,&D,&V,&csiz))<4) \
philpem@5 35255 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
philpem@5 35256 pixel_type(),filename?filename:("(FILE*)"),W,H,D,V); \
philpem@5 35257 if (W*H*D*V>0) { \
philpem@5 35258 CImg<Tss> raw; \
philpem@5 35259 CImg<T> &img = data[l]; \
philpem@5 35260 img.assign(W,H,D,V); \
philpem@5 35261 T *ptrd = img.data; \
philpem@5 35262 if (err==5) _cimgz_load_cimg_case(Tss) \
philpem@5 35263 else for (int toread = (int)img.size(); toread>0; ) { \
philpem@5 35264 raw.assign(cimg::min(toread,cimg_iobuffer)); \
philpem@5 35265 cimg::fread(raw.data,raw.width,nfile); \
philpem@5 35266 if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
philpem@5 35267 toread-=raw.width; \
philpem@5 35268 const Tss *ptrs = raw.data; \
philpem@5 35269 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
philpem@5 35270 } \
philpem@5 35271 } \
philpem@5 35272 } \
philpem@5 35273 loaded = true; \
philpem@5 35274 }
philpem@5 35275
philpem@5 35276 if (!filename && !file)
philpem@5 35277 throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
philpem@5 35278 pixel_type());
philpem@5 35279 typedef unsigned char uchar;
philpem@5 35280 typedef unsigned short ushort;
philpem@5 35281 typedef unsigned int uint;
philpem@5 35282 typedef unsigned long ulong;
philpem@5 35283 const int cimg_iobuffer = 12*1024*1024;
philpem@5 35284 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 35285 bool loaded = false, endian = cimg::endianness();
philpem@5 35286 char tmp[256], str_pixeltype[256], str_endian[256];
philpem@5 35287 unsigned int j, err, N = 0, W, H, D, V, csiz;
philpem@5 35288 int i;
philpem@5 35289 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
philpem@5 35290 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
philpem@5 35291 if (err<2) {
philpem@5 35292 if (!file) cimg::fclose(nfile);
philpem@5 35293 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
philpem@5 35294 pixel_type(),filename?filename:"(FILE*)");
philpem@5 35295 }
philpem@5 35296 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
philpem@5 35297 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
philpem@5 35298 assign(N);
philpem@5 35299 _cimg_load_cimg_case("bool",bool);
philpem@5 35300 _cimg_load_cimg_case("unsigned_char",uchar);
philpem@5 35301 _cimg_load_cimg_case("uchar",uchar);
philpem@5 35302 _cimg_load_cimg_case("char",char);
philpem@5 35303 _cimg_load_cimg_case("unsigned_short",ushort);
philpem@5 35304 _cimg_load_cimg_case("ushort",ushort);
philpem@5 35305 _cimg_load_cimg_case("short",short);
philpem@5 35306 _cimg_load_cimg_case("unsigned_int",uint);
philpem@5 35307 _cimg_load_cimg_case("uint",uint);
philpem@5 35308 _cimg_load_cimg_case("int",int);
philpem@5 35309 _cimg_load_cimg_case("unsigned_long",ulong);
philpem@5 35310 _cimg_load_cimg_case("ulong",ulong);
philpem@5 35311 _cimg_load_cimg_case("long",long);
philpem@5 35312 _cimg_load_cimg_case("float",float);
philpem@5 35313 _cimg_load_cimg_case("double",double);
philpem@5 35314 if (!loaded) {
philpem@5 35315 if (!file) cimg::fclose(nfile);
philpem@5 35316 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
philpem@5 35317 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
philpem@5 35318 }
philpem@5 35319 if (!file) cimg::fclose(nfile);
philpem@5 35320 return *this;
philpem@5 35321 }
philpem@5 35322
philpem@5 35323 //! Load a sub-image list from a non compressed .cimg file.
philpem@5 35324 CImgList<T>& load_cimg(const char *const filename,
philpem@5 35325 const unsigned int n0, const unsigned int n1,
philpem@5 35326 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 35327 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
philpem@5 35328 return _load_cimg(0,filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 35329 }
philpem@5 35330
philpem@5 35331 static CImgList<T> get_load_cimg(const char *const filename,
philpem@5 35332 const unsigned int n0, const unsigned int n1,
philpem@5 35333 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 35334 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
philpem@5 35335 return CImgList<T>().load_cimg(filename,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 35336 }
philpem@5 35337
philpem@5 35338 //! Load a sub-image list from a non compressed .cimg file.
philpem@5 35339 CImgList<T>& load_cimg(cimg_std::FILE *const file,
philpem@5 35340 const unsigned int n0, const unsigned int n1,
philpem@5 35341 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 35342 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
philpem@5 35343 return _load_cimg(file,0,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 35344 }
philpem@5 35345
philpem@5 35346 static CImgList<T> get_load_cimg(cimg_std::FILE *const file,
philpem@5 35347 const unsigned int n0, const unsigned int n1,
philpem@5 35348 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 35349 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
philpem@5 35350 return CImgList<T>().load_cimg(file,n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 35351 }
philpem@5 35352
philpem@5 35353 CImgList<T>& _load_cimg(cimg_std::FILE *const file, const char *const filename,
philpem@5 35354 const unsigned int n0, const unsigned int n1,
philpem@5 35355 const unsigned int x0, const unsigned int y0, const unsigned int z0, const unsigned int v0,
philpem@5 35356 const unsigned int x1, const unsigned int y1, const unsigned int z1, const unsigned int v1) {
philpem@5 35357 #define _cimg_load_cimg_case2(Ts,Tss) \
philpem@5 35358 if (!loaded && !cimg::strcasecmp(Ts,str_pixeltype)) { \
philpem@5 35359 for (unsigned int l = 0; l<=nn1; ++l) { \
philpem@5 35360 j = 0; while ((i=cimg_std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = '\0'; \
philpem@5 35361 W = H = D = V = 0; \
philpem@5 35362 if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
philpem@5 35363 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
philpem@5 35364 pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
philpem@5 35365 if (W*H*D*V>0) { \
philpem@5 35366 if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
philpem@5 35367 else { \
philpem@5 35368 const unsigned int \
philpem@5 35369 nx1 = x1>=W?W-1:x1, \
philpem@5 35370 ny1 = y1>=H?H-1:y1, \
philpem@5 35371 nz1 = z1>=D?D-1:z1, \
philpem@5 35372 nv1 = v1>=V?V-1:v1; \
philpem@5 35373 CImg<Tss> raw(1+nx1-x0); \
philpem@5 35374 CImg<T> &img = data[l-n0]; \
philpem@5 35375 img.assign(1+nx1-x0,1+ny1-y0,1+nz1-z0,1+nv1-v0); \
philpem@5 35376 T *ptrd = img.data; \
philpem@5 35377 const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
philpem@5 35378 if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
philpem@5 35379 for (unsigned int v=1+nv1-v0; v; --v) { \
philpem@5 35380 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
philpem@5 35381 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
philpem@5 35382 for (unsigned int z=1+nz1-z0; z; --z) { \
philpem@5 35383 const unsigned int skipyb = y0*W*sizeof(Tss); \
philpem@5 35384 if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
philpem@5 35385 for (unsigned int y=1+ny1-y0; y; --y) { \
philpem@5 35386 const unsigned int skipxb = x0*sizeof(Tss); \
philpem@5 35387 if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
philpem@5 35388 cimg::fread(raw.data,raw.width,nfile); \
philpem@5 35389 if (endian!=cimg::endianness()) cimg::invert_endianness(raw.data,raw.width); \
philpem@5 35390 const Tss *ptrs = raw.data; \
philpem@5 35391 for (unsigned int off = raw.width; off; --off) *(ptrd++) = (T)*(ptrs++); \
philpem@5 35392 const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
philpem@5 35393 if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
philpem@5 35394 } \
philpem@5 35395 const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
philpem@5 35396 if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
philpem@5 35397 } \
philpem@5 35398 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
philpem@5 35399 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
philpem@5 35400 } \
philpem@5 35401 const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
philpem@5 35402 if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
philpem@5 35403 } \
philpem@5 35404 } \
philpem@5 35405 } \
philpem@5 35406 loaded = true; \
philpem@5 35407 }
philpem@5 35408
philpem@5 35409 if (!filename && !file)
philpem@5 35410 throw CImgArgumentException("CImgList<%s>::load_cimg() : Cannot load (null) filename.",
philpem@5 35411 pixel_type());
philpem@5 35412 typedef unsigned char uchar;
philpem@5 35413 typedef unsigned short ushort;
philpem@5 35414 typedef unsigned int uint;
philpem@5 35415 typedef unsigned long ulong;
philpem@5 35416 if (n1<n0 || x1<x0 || y1<y0 || z1<z0 || v1<v0)
philpem@5 35417 throw CImgArgumentException("CImgList<%s>::load_cimg() : File '%s', Bad sub-region coordinates [%u->%u] "
philpem@5 35418 "(%u,%u,%u,%u)->(%u,%u,%u,%u).",
philpem@5 35419 pixel_type(),filename?filename:"(FILE*)",
philpem@5 35420 n0,n1,x0,y0,z0,v0,x1,y1,z1,v1);
philpem@5 35421 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 35422 bool loaded = false, endian = cimg::endianness();
philpem@5 35423 char tmp[256], str_pixeltype[256], str_endian[256];
philpem@5 35424 unsigned int j, err, N, W, H, D, V;
philpem@5 35425 int i;
philpem@5 35426 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
philpem@5 35427 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
philpem@5 35428 if (err<2) {
philpem@5 35429 if (!file) cimg::fclose(nfile);
philpem@5 35430 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.",
philpem@5 35431 pixel_type(),filename?filename:"(FILE*)");
philpem@5 35432 }
philpem@5 35433 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
philpem@5 35434 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
philpem@5 35435 const unsigned int nn1 = n1>=N?N-1:n1;
philpem@5 35436 assign(1+nn1-n0);
philpem@5 35437 _cimg_load_cimg_case2("bool",bool);
philpem@5 35438 _cimg_load_cimg_case2("unsigned_char",uchar);
philpem@5 35439 _cimg_load_cimg_case2("uchar",uchar);
philpem@5 35440 _cimg_load_cimg_case2("char",char);
philpem@5 35441 _cimg_load_cimg_case2("unsigned_short",ushort);
philpem@5 35442 _cimg_load_cimg_case2("ushort",ushort);
philpem@5 35443 _cimg_load_cimg_case2("short",short);
philpem@5 35444 _cimg_load_cimg_case2("unsigned_int",uint);
philpem@5 35445 _cimg_load_cimg_case2("uint",uint);
philpem@5 35446 _cimg_load_cimg_case2("int",int);
philpem@5 35447 _cimg_load_cimg_case2("unsigned_long",ulong);
philpem@5 35448 _cimg_load_cimg_case2("ulong",ulong);
philpem@5 35449 _cimg_load_cimg_case2("long",long);
philpem@5 35450 _cimg_load_cimg_case2("float",float);
philpem@5 35451 _cimg_load_cimg_case2("double",double);
philpem@5 35452 if (!loaded) {
philpem@5 35453 if (!file) cimg::fclose(nfile);
philpem@5 35454 throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.",
philpem@5 35455 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
philpem@5 35456 }
philpem@5 35457 if (!file) cimg::fclose(nfile);
philpem@5 35458 return *this;
philpem@5 35459 }
philpem@5 35460
philpem@5 35461 //! Load an image list from a PAR/REC (Philips) file.
philpem@5 35462 CImgList<T>& load_parrec(const char *const filename) {
philpem@5 35463 if (!filename)
philpem@5 35464 throw CImgArgumentException("CImgList<%s>::load_parrec() : Cannot load (null) filename.",
philpem@5 35465 pixel_type());
philpem@5 35466 char body[1024], filenamepar[1024], filenamerec[1024];
philpem@5 35467 const char *ext = cimg::split_filename(filename,body);
philpem@5 35468 if (!cimg::strcmp(ext,"par")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.rec",body); }
philpem@5 35469 if (!cimg::strcmp(ext,"PAR")) { cimg_std::strcpy(filenamepar,filename); cimg_std::sprintf(filenamerec,"%s.REC",body); }
philpem@5 35470 if (!cimg::strcmp(ext,"rec")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.par",body); }
philpem@5 35471 if (!cimg::strcmp(ext,"REC")) { cimg_std::strcpy(filenamerec,filename); cimg_std::sprintf(filenamepar,"%s.PAR",body); }
philpem@5 35472 cimg_std::FILE *file = cimg::fopen(filenamepar,"r");
philpem@5 35473
philpem@5 35474 // Parse header file
philpem@5 35475 CImgList<floatT> st_slices;
philpem@5 35476 CImgList<uintT> st_global;
philpem@5 35477 int err;
philpem@5 35478 char line[256] = { 0 };
philpem@5 35479 do { err=cimg_std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.'));
philpem@5 35480 do {
philpem@5 35481 unsigned int sn,sizex,sizey,pixsize;
philpem@5 35482 float rs,ri,ss;
philpem@5 35483 err = cimg_std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss);
philpem@5 35484 if (err==7) {
philpem@5 35485 st_slices.insert(CImg<floatT>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,
philpem@5 35486 ri,rs,ss,0));
philpem@5 35487 unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; ++i) {}
philpem@5 35488 if (i==st_global.size) st_global.insert(CImg<uintT>::vector(sizex,sizey,sn));
philpem@5 35489 else {
philpem@5 35490 CImg<uintT> &vec = st_global[i];
philpem@5 35491 if (sizex>vec[0]) vec[0] = sizex;
philpem@5 35492 if (sizey>vec[1]) vec[1] = sizey;
philpem@5 35493 vec[2] = sn;
philpem@5 35494 }
philpem@5 35495 st_slices[st_slices.size-1][7] = (float)i;
philpem@5 35496 }
philpem@5 35497 } while (err==7);
philpem@5 35498
philpem@5 35499 // Read data
philpem@5 35500 cimg_std::FILE *file2 = cimg::fopen(filenamerec,"rb");
philpem@5 35501 { cimglist_for(st_global,l) {
philpem@5 35502 const CImg<uintT>& vec = st_global[l];
philpem@5 35503 insert(CImg<T>(vec[0],vec[1],vec[2]));
philpem@5 35504 }}
philpem@5 35505
philpem@5 35506 cimglist_for(st_slices,l) {
philpem@5 35507 const CImg<floatT>& vec = st_slices[l];
philpem@5 35508 const unsigned int
philpem@5 35509 sn = (unsigned int)vec[0]-1,
philpem@5 35510 pixsize = (unsigned int)vec[1],
philpem@5 35511 sizex = (unsigned int)vec[2],
philpem@5 35512 sizey = (unsigned int)vec[3],
philpem@5 35513 imn = (unsigned int)vec[7];
philpem@5 35514 const float ri = vec[4], rs = vec[5], ss = vec[6];
philpem@5 35515 switch (pixsize) {
philpem@5 35516 case 8 : {
philpem@5 35517 CImg<ucharT> buf(sizex,sizey);
philpem@5 35518 cimg::fread(buf.data,sizex*sizey,file2);
philpem@5 35519 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
philpem@5 35520 CImg<T>& img = (*this)[imn];
philpem@5 35521 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
philpem@5 35522 } break;
philpem@5 35523 case 16 : {
philpem@5 35524 CImg<ushortT> buf(sizex,sizey);
philpem@5 35525 cimg::fread(buf.data,sizex*sizey,file2);
philpem@5 35526 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
philpem@5 35527 CImg<T>& img = (*this)[imn];
philpem@5 35528 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
philpem@5 35529 } break;
philpem@5 35530 case 32 : {
philpem@5 35531 CImg<uintT> buf(sizex,sizey);
philpem@5 35532 cimg::fread(buf.data,sizex*sizey,file2);
philpem@5 35533 if (cimg::endianness()) cimg::invert_endianness(buf.data,sizex*sizey);
philpem@5 35534 CImg<T>& img = (*this)[imn];
philpem@5 35535 cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss));
philpem@5 35536 } break;
philpem@5 35537 default :
philpem@5 35538 cimg::fclose(file);
philpem@5 35539 cimg::fclose(file2);
philpem@5 35540 throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.",
philpem@5 35541 pixel_type(),filename,pixsize);
philpem@5 35542 }
philpem@5 35543 }
philpem@5 35544 cimg::fclose(file);
philpem@5 35545 cimg::fclose(file2);
philpem@5 35546 if (!size)
philpem@5 35547 throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.",
philpem@5 35548 pixel_type(),filename);
philpem@5 35549 return *this;
philpem@5 35550 }
philpem@5 35551
philpem@5 35552 static CImgList<T> get_load_parrec(const char *const filename) {
philpem@5 35553 return CImgList<T>().load_parrec(filename);
philpem@5 35554 }
philpem@5 35555
philpem@5 35556 //! Load an image sequence from a YUV file.
philpem@5 35557 CImgList<T>& load_yuv(const char *const filename,
philpem@5 35558 const unsigned int sizex, const unsigned int sizey,
philpem@5 35559 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35560 const unsigned int step_frame=1, const bool yuv2rgb=true) {
philpem@5 35561 return _load_yuv(0,filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
philpem@5 35562 }
philpem@5 35563
philpem@5 35564 static CImgList<T> get_load_yuv(const char *const filename,
philpem@5 35565 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 35566 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35567 const unsigned int step_frame=1, const bool yuv2rgb=true) {
philpem@5 35568 return CImgList<T>().load_yuv(filename,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
philpem@5 35569 }
philpem@5 35570
philpem@5 35571 //! Load an image sequence from a YUV file.
philpem@5 35572 CImgList<T>& load_yuv(cimg_std::FILE *const file,
philpem@5 35573 const unsigned int sizex, const unsigned int sizey,
philpem@5 35574 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35575 const unsigned int step_frame=1, const bool yuv2rgb=true) {
philpem@5 35576 return _load_yuv(file,0,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
philpem@5 35577 }
philpem@5 35578
philpem@5 35579 static CImgList<T> get_load_yuv(cimg_std::FILE *const file,
philpem@5 35580 const unsigned int sizex, const unsigned int sizey=1,
philpem@5 35581 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35582 const unsigned int step_frame=1, const bool yuv2rgb=true) {
philpem@5 35583 return CImgList<T>().load_yuv(file,sizex,sizey,first_frame,last_frame,step_frame,yuv2rgb);
philpem@5 35584 }
philpem@5 35585
philpem@5 35586 CImgList<T>& _load_yuv(cimg_std::FILE *const file, const char *const filename,
philpem@5 35587 const unsigned int sizex, const unsigned int sizey,
philpem@5 35588 const unsigned int first_frame, const unsigned int last_frame,
philpem@5 35589 const unsigned int step_frame, const bool yuv2rgb) {
philpem@5 35590 if (!filename && !file)
philpem@5 35591 throw CImgArgumentException("CImgList<%s>::load_yuv() : Cannot load (null) filename.",
philpem@5 35592 pixel_type());
philpem@5 35593 if (sizex%2 || sizey%2)
philpem@5 35594 throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be "
philpem@5 35595 "even numbers (given are %ux%u)\n",
philpem@5 35596 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
philpem@5 35597 if (!sizex || !sizey)
philpem@5 35598 throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid",
philpem@5 35599 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
philpem@5 35600
philpem@5 35601 const unsigned int
philpem@5 35602 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
philpem@5 35603 nlast_frame = first_frame<last_frame?last_frame:first_frame,
philpem@5 35604 nstep_frame = step_frame?step_frame:1;
philpem@5 35605
philpem@5 35606 CImg<ucharT> tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2);
philpem@5 35607 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb");
philpem@5 35608 bool stopflag = false;
philpem@5 35609 int err;
philpem@5 35610 if (nfirst_frame) {
philpem@5 35611 err = cimg_std::fseek(nfile,nfirst_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
philpem@5 35612 if (err) {
philpem@5 35613 if (!file) cimg::fclose(nfile);
philpem@5 35614 throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u "
philpem@5 35615 "(out of range error).",
philpem@5 35616 pixel_type(),filename?filename:"(FILE*)",nfirst_frame);
philpem@5 35617 }
philpem@5 35618 }
philpem@5 35619 unsigned int frame;
philpem@5 35620 for (frame = nfirst_frame; !stopflag && frame<=nlast_frame; frame+=nstep_frame) {
philpem@5 35621 tmp.fill(0);
philpem@5 35622 // *TRY* to read the luminance part, do not replace by cimg::fread !
philpem@5 35623 err = (int)cimg_std::fread((void*)(tmp.data),1,(size_t)(tmp.width*tmp.height),nfile);
philpem@5 35624 if (err!=(int)(tmp.width*tmp.height)) {
philpem@5 35625 stopflag = true;
philpem@5 35626 if (err>0)
philpem@5 35627 cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
philpem@5 35628 " or given image dimensions (%u,%u) are incorrect.",
philpem@5 35629 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
philpem@5 35630 } else {
philpem@5 35631 UV.fill(0);
philpem@5 35632 // *TRY* to read the luminance part, do not replace by cimg::fread !
philpem@5 35633 err = (int)cimg_std::fread((void*)(UV.data),1,(size_t)(UV.size()),nfile);
philpem@5 35634 if (err!=(int)(UV.size())) {
philpem@5 35635 stopflag = true;
philpem@5 35636 if (err>0)
philpem@5 35637 cimg::warn("CImgList<%s>::load_yuv() : File '%s' contains incomplete data,"
philpem@5 35638 " or given image dimensions (%u,%u) are incorrect.",
philpem@5 35639 pixel_type(),filename?filename:"(FILE*)",sizex,sizey);
philpem@5 35640 } else {
philpem@5 35641 cimg_forXY(UV,x,y) {
philpem@5 35642 const int x2 = x*2, y2 = y*2;
philpem@5 35643 tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0);
philpem@5 35644 tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1);
philpem@5 35645 }
philpem@5 35646 if (yuv2rgb) tmp.YCbCrtoRGB();
philpem@5 35647 insert(tmp);
philpem@5 35648 if (nstep_frame>1) cimg_std::fseek(nfile,(nstep_frame-1)*(sizex*sizey + sizex*sizey/2),SEEK_CUR);
philpem@5 35649 }
philpem@5 35650 }
philpem@5 35651 }
philpem@5 35652 if (stopflag && nlast_frame!=~0U && frame!=nlast_frame)
philpem@5 35653 cimg::warn("CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.",
philpem@5 35654 pixel_type(),filename?filename:"(FILE*)",nlast_frame,frame-1,filename);
philpem@5 35655 if (!file) cimg::fclose(nfile);
philpem@5 35656 return *this;
philpem@5 35657 }
philpem@5 35658
philpem@5 35659 //! Load an image from a video file, using ffmpeg libraries.
philpem@5 35660 // This piece of code has been firstly created by David Starweather (starkdg(at)users(dot)sourceforge(dot)net)
philpem@5 35661 // I modified it afterwards for direct inclusion in the library core.
philpem@5 35662 CImgList<T>& load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35663 const unsigned int step_frame=1, const bool pixel_format=true, const bool resume=false) {
philpem@5 35664 if (!filename)
philpem@5 35665 throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : Cannot load (null) filename.",
philpem@5 35666 pixel_type());
philpem@5 35667 const unsigned int
philpem@5 35668 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
philpem@5 35669 nlast_frame = first_frame<last_frame?last_frame:first_frame,
philpem@5 35670 nstep_frame = step_frame?step_frame:1;
philpem@5 35671 assign();
philpem@5 35672
philpem@5 35673 #ifndef cimg_use_ffmpeg
philpem@5 35674 if ((nfirst_frame || nlast_frame!=~0U || nstep_frame>1) || (resume && (pixel_format || !pixel_format)))
philpem@5 35675 throw CImgArgumentException("CImg<%s>::load_ffmpeg() : File '%s', reading sub-frames from a video file requires the use of ffmpeg.\n"
philpem@5 35676 "('cimg_use_ffmpeg' must be defined).",
philpem@5 35677 pixel_type(),filename);
philpem@5 35678 return load_ffmpeg_external(filename);
philpem@5 35679 #else
philpem@5 35680 const unsigned int ffmpeg_pixfmt = pixel_format?PIX_FMT_RGB24:PIX_FMT_GRAY8;
philpem@5 35681 avcodec_register_all();
philpem@5 35682 av_register_all();
philpem@5 35683 static AVFormatContext *format_ctx = 0;
philpem@5 35684 static AVCodecContext *codec_ctx = 0;
philpem@5 35685 static AVCodec *codec = 0;
philpem@5 35686 static AVFrame *avframe = avcodec_alloc_frame(), *converted_frame = avcodec_alloc_frame();
philpem@5 35687 static int vstream = 0;
philpem@5 35688
philpem@5 35689 if (resume) {
philpem@5 35690 if (!format_ctx || !codec_ctx || !codec || !avframe || !converted_frame)
philpem@5 35691 throw CImgArgumentException("CImgList<%s>::load_ffmpeg() : File '%s', cannot resume due to unallocated FFMPEG structures.",
philpem@5 35692 pixel_type(),filename);
philpem@5 35693 } else {
philpem@5 35694 // Open video file, find main video stream and codec.
philpem@5 35695 if (format_ctx) av_close_input_file(format_ctx);
philpem@5 35696 if (av_open_input_file(&format_ctx,filename,0,0,0)!=0)
philpem@5 35697 throw CImgIOException("CImgList<%s>::load_ffmpeg() : File '%s' cannot be opened.",
philpem@5 35698 pixel_type(),filename);
philpem@5 35699 if (!avframe || !converted_frame || av_find_stream_info(format_ctx)<0) {
philpem@5 35700 av_close_input_file(format_ctx); format_ctx = 0;
philpem@5 35701 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve stream information.\n"
philpem@5 35702 "Trying with external ffmpeg executable.",
philpem@5 35703 pixel_type(),filename);
philpem@5 35704 return load_ffmpeg_external(filename);
philpem@5 35705 }
philpem@5 35706 #if cimg_debug>=3
philpem@5 35707 dump_format(format_ctx,0,0,0);
philpem@5 35708 #endif
philpem@5 35709
philpem@5 35710 // Special command : Return informations on main video stream.
philpem@5 35711 // as a vector 1x4 containing : (nb_frames,width,height,fps).
philpem@5 35712 if (!first_frame && !last_frame && !step_frame) {
philpem@5 35713 for (vstream = 0; vstream<(int)(format_ctx->nb_streams); ++vstream)
philpem@5 35714 if (format_ctx->streams[vstream]->codec->codec_type==CODEC_TYPE_VIDEO) break;
philpem@5 35715 if (vstream==(int)format_ctx->nb_streams) assign();
philpem@5 35716 else {
philpem@5 35717 CImgList<doubleT> timestamps;
philpem@5 35718 int nb_frames;
philpem@5 35719 AVPacket packet;
philpem@5 35720 // Count frames and store timestamps.
philpem@5 35721 for (nb_frames = 0; av_read_frame(format_ctx,&packet)>=0; av_free_packet(&packet))
philpem@5 35722 if (packet.stream_index==vstream) {
philpem@5 35723 timestamps.insert(CImg<doubleT>::vector((double)packet.pts));
philpem@5 35724 ++nb_frames;
philpem@5 35725 }
philpem@5 35726 // Get frame with, height and fps.
philpem@5 35727 const int
philpem@5 35728 framew = format_ctx->streams[vstream]->codec->width,
philpem@5 35729 frameh = format_ctx->streams[vstream]->codec->height;
philpem@5 35730 const float
philpem@5 35731 num = (float)(format_ctx->streams[vstream]->r_frame_rate).num,
philpem@5 35732 den = (float)(format_ctx->streams[vstream]->r_frame_rate).den,
philpem@5 35733 fps = num/den;
philpem@5 35734 // Return infos as a list.
philpem@5 35735 assign(2);
philpem@5 35736 (*this)[0].assign(1,4).fill((T)nb_frames,(T)framew,(T)frameh,(T)fps);
philpem@5 35737 (*this)[1] = timestamps.get_append('y');
philpem@5 35738 }
philpem@5 35739 av_close_input_file(format_ctx); format_ctx = 0;
philpem@5 35740 return *this;
philpem@5 35741 }
philpem@5 35742
philpem@5 35743 for (vstream = 0; vstream<(int)(format_ctx->nb_streams) &&
philpem@5 35744 format_ctx->streams[vstream]->codec->codec_type!=CODEC_TYPE_VIDEO; ) ++vstream;
philpem@5 35745 if (vstream==(int)format_ctx->nb_streams) {
philpem@5 35746 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot retrieve video stream.\n"
philpem@5 35747 "Trying with external ffmpeg executable.",
philpem@5 35748 pixel_type(),filename);
philpem@5 35749 av_close_input_file(format_ctx); format_ctx = 0;
philpem@5 35750 return load_ffmpeg_external(filename);
philpem@5 35751 }
philpem@5 35752 codec_ctx = format_ctx->streams[vstream]->codec;
philpem@5 35753 codec = avcodec_find_decoder(codec_ctx->codec_id);
philpem@5 35754 if (!codec) {
philpem@5 35755 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot find video codec.\n"
philpem@5 35756 "Trying with external ffmpeg executable.",
philpem@5 35757 pixel_type(),filename);
philpem@5 35758 return load_ffmpeg_external(filename);
philpem@5 35759 }
philpem@5 35760 if (avcodec_open(codec_ctx,codec)<0) { // Open codec
philpem@5 35761 cimg::warn("CImgList<%s>::load_ffmpeg() : File '%s', cannot open video codec.\n"
philpem@5 35762 "Trying with external ffmpeg executable.",
philpem@5 35763 pixel_type(),filename);
philpem@5 35764 return load_ffmpeg_external(filename);
philpem@5 35765 }
philpem@5 35766 }
philpem@5 35767
philpem@5 35768 // Read video frames
philpem@5 35769 const unsigned int numBytes = avpicture_get_size(ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
philpem@5 35770 uint8_t *const buffer = new uint8_t[numBytes];
philpem@5 35771 avpicture_fill((AVPicture *)converted_frame,buffer,ffmpeg_pixfmt,codec_ctx->width,codec_ctx->height);
philpem@5 35772 const T foo = (T)0;
philpem@5 35773 AVPacket packet;
philpem@5 35774 for (unsigned int frame = 0, next_frame = nfirst_frame; frame<=nlast_frame && av_read_frame(format_ctx,&packet)>=0; ) {
philpem@5 35775 if (packet.stream_index==(int)vstream) {
philpem@5 35776 int decoded = 0;
philpem@5 35777 avcodec_decode_video(codec_ctx,avframe,&decoded,packet.data,packet.size);
philpem@5 35778 if (decoded) {
philpem@5 35779 if (frame==next_frame) {
philpem@5 35780 SwsContext *c = sws_getContext(codec_ctx->width,codec_ctx->height,codec_ctx->pix_fmt,codec_ctx->width,
philpem@5 35781 codec_ctx->height,ffmpeg_pixfmt,1,0,0,0);
philpem@5 35782 sws_scale(c,avframe->data,avframe->linesize,0,codec_ctx->height,converted_frame->data,converted_frame->linesize);
philpem@5 35783 if (ffmpeg_pixfmt==PIX_FMT_RGB24) {
philpem@5 35784 CImg<ucharT> next_image(*converted_frame->data,3,codec_ctx->width,codec_ctx->height,1,true);
philpem@5 35785 insert(next_image._get_permute_axes("yzvx",foo));
philpem@5 35786 } else {
philpem@5 35787 CImg<ucharT> next_image(*converted_frame->data,1,codec_ctx->width,codec_ctx->height,1,true);
philpem@5 35788 insert(next_image._get_permute_axes("yzvx",foo));
philpem@5 35789 }
philpem@5 35790 next_frame+=nstep_frame;
philpem@5 35791 }
philpem@5 35792 ++frame;
philpem@5 35793 }
philpem@5 35794 av_free_packet(&packet);
philpem@5 35795 if (next_frame>nlast_frame) break;
philpem@5 35796 }
philpem@5 35797 }
philpem@5 35798 delete[] buffer;
philpem@5 35799 #endif
philpem@5 35800 return *this;
philpem@5 35801 }
philpem@5 35802
philpem@5 35803 static CImgList<T> get_load_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35804 const unsigned int step_frame=1, const bool pixel_format=true) {
philpem@5 35805 return CImgList<T>().load_ffmpeg(filename,first_frame,last_frame,step_frame,pixel_format);
philpem@5 35806 }
philpem@5 35807
philpem@5 35808 //! Load an image from a video file (MPEG,AVI) using the external tool 'ffmpeg'.
philpem@5 35809 CImgList<T>& load_ffmpeg_external(const char *const filename) {
philpem@5 35810 if (!filename)
philpem@5 35811 throw CImgArgumentException("CImgList<%s>::load_ffmpeg_external() : Cannot load (null) filename.",
philpem@5 35812 pixel_type());
philpem@5 35813 char command[1024], filetmp[512], filetmp2[512];
philpem@5 35814 cimg_std::FILE *file = 0;
philpem@5 35815 do {
philpem@5 35816 cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 35817 cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
philpem@5 35818 if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
philpem@5 35819 } while (file);
philpem@5 35820 cimg_std::sprintf(filetmp2,"%s_%%6d.ppm",filetmp);
philpem@5 35821 #if cimg_OS!=2
philpem@5 35822 cimg_std::sprintf(command,"%s -i \"%s\" %s >/dev/null 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
philpem@5 35823 #else
philpem@5 35824 cimg_std::sprintf(command,"\"%s -i \"%s\" %s\" >NUL 2>&1",cimg::ffmpeg_path(),filename,filetmp2);
philpem@5 35825 #endif
philpem@5 35826 cimg::system(command,0);
philpem@5 35827 const unsigned int odebug = cimg::exception_mode();
philpem@5 35828 cimg::exception_mode() = 0;
philpem@5 35829 assign();
philpem@5 35830 unsigned int i = 1;
philpem@5 35831 for (bool stopflag = false; !stopflag; ++i) {
philpem@5 35832 cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,i);
philpem@5 35833 CImg<T> img;
philpem@5 35834 try { img.load_pnm(filetmp2); }
philpem@5 35835 catch (CImgException&) { stopflag = true; }
philpem@5 35836 if (img) { insert(img); cimg_std::remove(filetmp2); }
philpem@5 35837 }
philpem@5 35838 cimg::exception_mode() = odebug;
philpem@5 35839 if (is_empty())
philpem@5 35840 throw CImgIOException("CImgList<%s>::load_ffmpeg_external() : Failed to open image sequence '%s'.\n"
philpem@5 35841 "Check the filename and if the 'ffmpeg' tool is installed on your system.",
philpem@5 35842 pixel_type(),filename);
philpem@5 35843 return *this;
philpem@5 35844 }
philpem@5 35845
philpem@5 35846 static CImgList<T> get_load_ffmpeg_external(const char *const filename) {
philpem@5 35847 return CImgList<T>().load_ffmpeg_external(filename);
philpem@5 35848 }
philpem@5 35849
philpem@5 35850 //! Load a gzipped list, using external tool 'gunzip'.
philpem@5 35851 CImgList<T>& load_gzip_external(const char *const filename) {
philpem@5 35852 if (!filename)
philpem@5 35853 throw CImgIOException("CImg<%s>::load_gzip_external() : Cannot load (null) filename.",
philpem@5 35854 pixel_type());
philpem@5 35855 char command[1024], filetmp[512], body[512];
philpem@5 35856 const char
philpem@5 35857 *ext = cimg::split_filename(filename,body),
philpem@5 35858 *ext2 = cimg::split_filename(body,0);
philpem@5 35859 cimg_std::FILE *file = 0;
philpem@5 35860 do {
philpem@5 35861 if (!cimg::strcasecmp(ext,"gz")) {
philpem@5 35862 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 35863 cimg::filenamerand(),ext2);
philpem@5 35864 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 35865 cimg::filenamerand());
philpem@5 35866 } else {
philpem@5 35867 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 35868 cimg::filenamerand(),ext);
philpem@5 35869 else cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 35870 cimg::filenamerand());
philpem@5 35871 }
philpem@5 35872 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 35873 } while (file);
philpem@5 35874 cimg_std::sprintf(command,"%s -c \"%s\" > %s",cimg::gunzip_path(),filename,filetmp);
philpem@5 35875 cimg::system(command);
philpem@5 35876 if (!(file = cimg_std::fopen(filetmp,"rb"))) {
philpem@5 35877 cimg::fclose(cimg::fopen(filename,"r"));
philpem@5 35878 throw CImgIOException("CImg<%s>::load_gzip_external() : File '%s' cannot be opened.",
philpem@5 35879 pixel_type(),filename);
philpem@5 35880 } else cimg::fclose(file);
philpem@5 35881 load(filetmp);
philpem@5 35882 cimg_std::remove(filetmp);
philpem@5 35883 return *this;
philpem@5 35884 }
philpem@5 35885
philpem@5 35886 static CImgList<T> get_load_gzip_external(const char *const filename) {
philpem@5 35887 return CImgList<T>().load_gzip_external(filename);
philpem@5 35888 }
philpem@5 35889
philpem@5 35890 //! Load a 3D object from a .OFF file.
philpem@5 35891 template<typename tf, typename tc>
philpem@5 35892 CImgList<T>& load_off(const char *const filename,
philpem@5 35893 CImgList<tf>& primitives, CImgList<tc>& colors,
philpem@5 35894 const bool invert_faces=false) {
philpem@5 35895 return get_load_off(filename,primitives,colors,invert_faces).transfer_to(*this);
philpem@5 35896 }
philpem@5 35897
philpem@5 35898 template<typename tf, typename tc>
philpem@5 35899 static CImgList<T> get_load_off(const char *const filename,
philpem@5 35900 CImgList<tf>& primitives, CImgList<tc>& colors,
philpem@5 35901 const bool invert_faces=false) {
philpem@5 35902 return CImg<T>().load_off(filename,primitives,colors,invert_faces).get_split('x');
philpem@5 35903 }
philpem@5 35904
philpem@5 35905 //! Load a TIFF file.
philpem@5 35906 CImgList<T>& load_tiff(const char *const filename,
philpem@5 35907 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35908 const unsigned int step_frame=1) {
philpem@5 35909 const unsigned int
philpem@5 35910 nfirst_frame = first_frame<last_frame?first_frame:last_frame,
philpem@5 35911 nstep_frame = step_frame?step_frame:1;
philpem@5 35912 unsigned int nlast_frame = first_frame<last_frame?last_frame:first_frame;
philpem@5 35913 #ifndef cimg_use_tiff
philpem@5 35914 if (nfirst_frame || nlast_frame!=~0U || nstep_frame!=1)
philpem@5 35915 throw CImgArgumentException("CImgList<%s>::load_tiff() : File '%s', reading sub-images from a tiff file requires the use of libtiff.\n"
philpem@5 35916 "('cimg_use_tiff' must be defined).",
philpem@5 35917 pixel_type(),filename);
philpem@5 35918 return assign(CImg<T>::get_load_tiff(filename));
philpem@5 35919 #else
philpem@5 35920 TIFF *tif = TIFFOpen(filename,"r");
philpem@5 35921 if (tif) {
philpem@5 35922 unsigned int nb_images = 0;
philpem@5 35923 do ++nb_images; while (TIFFReadDirectory(tif));
philpem@5 35924 if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images))
philpem@5 35925 cimg::warn("CImgList<%s>::load_tiff() : File '%s' contains %u image(s), specified frame range is [%u,%u] (step %u).",
philpem@5 35926 pixel_type(),filename,nb_images,nfirst_frame,nlast_frame,nstep_frame);
philpem@5 35927 if (nfirst_frame>=nb_images) return assign();
philpem@5 35928 if (nlast_frame>=nb_images) nlast_frame = nb_images-1;
philpem@5 35929 assign(1+(nlast_frame-nfirst_frame)/nstep_frame);
philpem@5 35930 TIFFSetDirectory(tif,0);
philpem@5 35931 #if cimg_debug>=3
philpem@5 35932 TIFFSetWarningHandler(0);
philpem@5 35933 TIFFSetErrorHandler(0);
philpem@5 35934 #endif
philpem@5 35935 cimglist_for(*this,l) data[l]._load_tiff(tif,nfirst_frame+l*nstep_frame);
philpem@5 35936 TIFFClose(tif);
philpem@5 35937 } else throw CImgException("CImgList<%s>::load_tiff() : File '%s' cannot be opened.",
philpem@5 35938 pixel_type(),filename);
philpem@5 35939 return *this;
philpem@5 35940 #endif
philpem@5 35941 }
philpem@5 35942
philpem@5 35943 static CImgList<T> get_load_tiff(const char *const filename,
philpem@5 35944 const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 35945 const unsigned int step_frame=1) {
philpem@5 35946 return CImgList<T>().load_tiff(filename,first_frame,last_frame,step_frame);
philpem@5 35947 }
philpem@5 35948
philpem@5 35949 //! Save an image list into a file.
philpem@5 35950 /**
philpem@5 35951 Depending on the extension of the given filename, a file format is chosen for the output file.
philpem@5 35952 **/
philpem@5 35953 const CImgList<T>& save(const char *const filename, const int number=-1) const {
philpem@5 35954 if (is_empty())
philpem@5 35955 throw CImgInstanceException("CImgList<%s>::save() : File '%s, instance list (%u,%p) is empty.",
philpem@5 35956 pixel_type(),filename?filename:"(null)",size,data);
philpem@5 35957 if (!filename)
philpem@5 35958 throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).",
philpem@5 35959 pixel_type(),size,data);
philpem@5 35960 const char *ext = cimg::split_filename(filename);
philpem@5 35961 char nfilename[1024];
philpem@5 35962 const char *const fn = (number>=0)?cimg::number_filename(filename,number,6,nfilename):filename;
philpem@5 35963 #ifdef cimglist_save_plugin
philpem@5 35964 cimglist_save_plugin(fn);
philpem@5 35965 #endif
philpem@5 35966 #ifdef cimglist_save_plugin1
philpem@5 35967 cimglist_save_plugin1(fn);
philpem@5 35968 #endif
philpem@5 35969 #ifdef cimglist_save_plugin2
philpem@5 35970 cimglist_save_plugin2(fn);
philpem@5 35971 #endif
philpem@5 35972 #ifdef cimglist_save_plugin3
philpem@5 35973 cimglist_save_plugin3(fn);
philpem@5 35974 #endif
philpem@5 35975 #ifdef cimglist_save_plugin4
philpem@5 35976 cimglist_save_plugin4(fn);
philpem@5 35977 #endif
philpem@5 35978 #ifdef cimglist_save_plugin5
philpem@5 35979 cimglist_save_plugin5(fn);
philpem@5 35980 #endif
philpem@5 35981 #ifdef cimglist_save_plugin6
philpem@5 35982 cimglist_save_plugin6(fn);
philpem@5 35983 #endif
philpem@5 35984 #ifdef cimglist_save_plugin7
philpem@5 35985 cimglist_save_plugin7(fn);
philpem@5 35986 #endif
philpem@5 35987 #ifdef cimglist_save_plugin8
philpem@5 35988 cimglist_save_plugin8(fn);
philpem@5 35989 #endif
philpem@5 35990 #ifdef cimg_use_tiff
philpem@5 35991 if (!cimg::strcasecmp(ext,"tif") ||
philpem@5 35992 !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn);
philpem@5 35993 #endif
philpem@5 35994 if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true);
philpem@5 35995 if (!cimg::strcasecmp(ext,"cimg") || !ext[0]) return save_cimg(fn,false);
philpem@5 35996 if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,true);
philpem@5 35997 if (!cimg::strcasecmp(ext,"avi") ||
philpem@5 35998 !cimg::strcasecmp(ext,"mov") ||
philpem@5 35999 !cimg::strcasecmp(ext,"asf") ||
philpem@5 36000 !cimg::strcasecmp(ext,"divx") ||
philpem@5 36001 !cimg::strcasecmp(ext,"flv") ||
philpem@5 36002 !cimg::strcasecmp(ext,"mpg") ||
philpem@5 36003 !cimg::strcasecmp(ext,"m1v") ||
philpem@5 36004 !cimg::strcasecmp(ext,"m2v") ||
philpem@5 36005 !cimg::strcasecmp(ext,"m4v") ||
philpem@5 36006 !cimg::strcasecmp(ext,"mjp") ||
philpem@5 36007 !cimg::strcasecmp(ext,"mkv") ||
philpem@5 36008 !cimg::strcasecmp(ext,"mpe") ||
philpem@5 36009 !cimg::strcasecmp(ext,"movie") ||
philpem@5 36010 !cimg::strcasecmp(ext,"ogm") ||
philpem@5 36011 !cimg::strcasecmp(ext,"qt") ||
philpem@5 36012 !cimg::strcasecmp(ext,"rm") ||
philpem@5 36013 !cimg::strcasecmp(ext,"vob") ||
philpem@5 36014 !cimg::strcasecmp(ext,"wmv") ||
philpem@5 36015 !cimg::strcasecmp(ext,"xvid") ||
philpem@5 36016 !cimg::strcasecmp(ext,"mpeg")) return save_ffmpeg(fn);
philpem@5 36017 if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn);
philpem@5 36018 if (size==1) data[0].save(fn,-1); else cimglist_for(*this,l) data[l].save(fn,l);
philpem@5 36019 return *this;
philpem@5 36020 }
philpem@5 36021
philpem@5 36022 //! Save an image sequence, using FFMPEG library.
philpem@5 36023 // This piece of code has been originally written by David. G. Starkweather.
philpem@5 36024 const CImgList<T>& save_ffmpeg(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 36025 const unsigned int fps=25) const {
philpem@5 36026 if (is_empty())
philpem@5 36027 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36028 pixel_type(),filename?filename:"(null)",size,data);
philpem@5 36029 if (!filename)
philpem@5 36030 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : Instance list (%u,%p), specified filename is (null).",
philpem@5 36031 pixel_type(),size,data);
philpem@5 36032 if (!fps)
philpem@5 36033 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified framerate is 0.",
philpem@5 36034 pixel_type(),filename);
philpem@5 36035 const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
philpem@5 36036 if (first_frame>=size || nlast_frame>=size)
philpem@5 36037 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
philpem@5 36038 pixel_type(),filename,first_frame,last_frame,size);
philpem@5 36039 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
philpem@5 36040 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', images of the sequence have different dimensions.",
philpem@5 36041 pixel_type(),filename);
philpem@5 36042
philpem@5 36043 #ifndef cimg_use_ffmpeg
philpem@5 36044 return save_ffmpeg_external(filename,first_frame,last_frame);
philpem@5 36045 #else
philpem@5 36046 avcodec_register_all();
philpem@5 36047 av_register_all();
philpem@5 36048 const int
philpem@5 36049 frame_dimx = data[first_frame].dimx(),
philpem@5 36050 frame_dimy = data[first_frame].dimy(),
philpem@5 36051 frame_dimv = data[first_frame].dimv();
philpem@5 36052 if (frame_dimv!=1 && frame_dimv!=3)
philpem@5 36053 throw CImgInstanceException("CImgList<%s>::save_ffmpeg() : File '%s', image[0] (%u,%u,%u,%u,%p) has not 1 or 3 channels.",
philpem@5 36054 pixel_type(),filename,data[0].width,data[0].height,data[0].depth,data[0].dim,data);
philpem@5 36055
philpem@5 36056 PixelFormat dest_pxl_fmt = PIX_FMT_YUV420P;
philpem@5 36057 PixelFormat src_pxl_fmt = (frame_dimv == 3)?PIX_FMT_RGB24:PIX_FMT_GRAY8;
philpem@5 36058
philpem@5 36059 int sws_flags = SWS_FAST_BILINEAR; // Interpolation method (keeping same size images for now).
philpem@5 36060 AVOutputFormat *fmt = 0;
philpem@5 36061 fmt = guess_format(0,filename,0);
philpem@5 36062 if (!fmt) fmt = guess_format("mpeg",0,0); // Default format "mpeg".
philpem@5 36063 if (!fmt)
philpem@5 36064 throw CImgArgumentException("CImgList<%s>::save_ffmpeg() : File '%s', could not determine file format from filename.",
philpem@5 36065 pixel_type(),filename);
philpem@5 36066
philpem@5 36067 AVFormatContext *oc = 0;
philpem@5 36068 oc = av_alloc_format_context();
philpem@5 36069 if (!oc) // Failed to allocate format context.
philpem@5 36070 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate structure for format context.",
philpem@5 36071 pixel_type(),filename);
philpem@5 36072
philpem@5 36073 AVCodec *codec = 0;
philpem@5 36074 AVFrame *picture = 0;
philpem@5 36075 AVFrame *tmp_pict = 0;
philpem@5 36076 oc->oformat = fmt;
philpem@5 36077 cimg_std::sprintf(oc->filename,"%s",filename);
philpem@5 36078
philpem@5 36079 // Add video stream.
philpem@5 36080 int stream_index = 0;
philpem@5 36081 AVStream *video_str = 0;
philpem@5 36082 if (fmt->video_codec!=CODEC_ID_NONE) {
philpem@5 36083 video_str = av_new_stream(oc,stream_index);
philpem@5 36084 if (!video_str) { // Failed to allocate stream.
philpem@5 36085 av_free(oc);
philpem@5 36086 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate video stream structure.",
philpem@5 36087 pixel_type(),filename);
philpem@5 36088 }
philpem@5 36089 } else { // No codec identified.
philpem@5 36090 av_free(oc);
philpem@5 36091 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no proper codec identified.",
philpem@5 36092 pixel_type(),filename);
philpem@5 36093 }
philpem@5 36094
philpem@5 36095 AVCodecContext *c = video_str->codec;
philpem@5 36096 c->codec_id = fmt->video_codec;
philpem@5 36097 c->codec_type = CODEC_TYPE_VIDEO;
philpem@5 36098 c->bit_rate = 400000;
philpem@5 36099 c->width = frame_dimx;
philpem@5 36100 c->height = frame_dimy;
philpem@5 36101 c->time_base.num = 1;
philpem@5 36102 c->time_base.den = fps;
philpem@5 36103 c->gop_size = 12;
philpem@5 36104 c->pix_fmt = dest_pxl_fmt;
philpem@5 36105 if (c->codec_id == CODEC_ID_MPEG2VIDEO) c->max_b_frames = 2;
philpem@5 36106 if (c->codec_id == CODEC_ID_MPEG1VIDEO) c->mb_decision = 2;
philpem@5 36107
philpem@5 36108 if (av_set_parameters(oc,0)<0) { // Parameters not properly set.
philpem@5 36109 av_free(oc);
philpem@5 36110 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', parameters for avcodec not properly set.",
philpem@5 36111 pixel_type(),filename);
philpem@5 36112 }
philpem@5 36113
philpem@5 36114 // Open codecs and alloc buffers.
philpem@5 36115 codec = avcodec_find_encoder(c->codec_id);
philpem@5 36116 if (!codec) { // Failed to find codec.
philpem@5 36117 av_free(oc);
philpem@5 36118 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', no codec found.",
philpem@5 36119 pixel_type(),filename);
philpem@5 36120 }
philpem@5 36121 if (avcodec_open(c,codec)<0) // Failed to open codec.
philpem@5 36122 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to open codec.",
philpem@5 36123 pixel_type(),filename);
philpem@5 36124 tmp_pict = avcodec_alloc_frame();
philpem@5 36125 if (!tmp_pict) { // Failed to allocate memory for tmp_pict frame.
philpem@5 36126 avcodec_close(video_str->codec);
philpem@5 36127 av_free(oc);
philpem@5 36128 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
philpem@5 36129 pixel_type(),filename);
philpem@5 36130 }
philpem@5 36131 tmp_pict->linesize[0] = (src_pxl_fmt==PIX_FMT_RGB24)?3*frame_dimx:frame_dimx;
philpem@5 36132 tmp_pict->type = FF_BUFFER_TYPE_USER;
philpem@5 36133 int tmp_size = avpicture_get_size(src_pxl_fmt,frame_dimx,frame_dimy);
philpem@5 36134 uint8_t *tmp_buffer = (uint8_t*)av_malloc(tmp_size);
philpem@5 36135 if (!tmp_buffer) { // Failed to allocate memory for tmp buffer.
philpem@5 36136 av_free(tmp_pict);
philpem@5 36137 avcodec_close(video_str->codec);
philpem@5 36138 av_free(oc);
philpem@5 36139 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for data buffer.",
philpem@5 36140 pixel_type(),filename);
philpem@5 36141 }
philpem@5 36142
philpem@5 36143 // Associate buffer with tmp_pict.
philpem@5 36144 avpicture_fill((AVPicture*)tmp_pict,tmp_buffer,src_pxl_fmt,frame_dimx,frame_dimy);
philpem@5 36145 picture = avcodec_alloc_frame();
philpem@5 36146 if (!picture) { // Failed to allocate picture frame.
philpem@5 36147 av_free(tmp_pict->data[0]);
philpem@5 36148 av_free(tmp_pict);
philpem@5 36149 avcodec_close(video_str->codec);
philpem@5 36150 av_free(oc);
philpem@5 36151 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame.",
philpem@5 36152 pixel_type(),filename);
philpem@5 36153 }
philpem@5 36154
philpem@5 36155 int size = avpicture_get_size(c->pix_fmt,frame_dimx,frame_dimy);
philpem@5 36156 uint8_t *buffer = (uint8_t*)av_malloc(size);
philpem@5 36157 if (!buffer) { // Failed to allocate picture frame buffer.
philpem@5 36158 av_free(picture);
philpem@5 36159 av_free(tmp_pict->data[0]);
philpem@5 36160 av_free(tmp_pict);
philpem@5 36161 avcodec_close(video_str->codec);
philpem@5 36162 av_free(oc);
philpem@5 36163 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to allocate memory for picture frame buffer.",
philpem@5 36164 pixel_type(),filename);
philpem@5 36165 }
philpem@5 36166
philpem@5 36167 // Associate the buffer with picture.
philpem@5 36168 avpicture_fill((AVPicture*)picture,buffer,c->pix_fmt,frame_dimx,frame_dimy);
philpem@5 36169
philpem@5 36170 // Open file.
philpem@5 36171 if (!(fmt->flags&AVFMT_NOFILE)) {
philpem@5 36172 if (url_fopen(&oc->pb,filename,URL_WRONLY)<0)
philpem@5 36173 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s' cannot be opened.",
philpem@5 36174 pixel_type(),filename);
philpem@5 36175 }
philpem@5 36176
philpem@5 36177 if (av_write_header(oc)<0)
philpem@5 36178 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', could not write header.",
philpem@5 36179 pixel_type(),filename);
philpem@5 36180 double video_pts;
philpem@5 36181 SwsContext *img_convert_context = 0;
philpem@5 36182 img_convert_context = sws_getContext(frame_dimx,frame_dimy,src_pxl_fmt,
philpem@5 36183 c->width,c->height,c->pix_fmt,sws_flags,0,0,0);
philpem@5 36184 if (!img_convert_context) { // Failed to get swscale context.
philpem@5 36185 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
philpem@5 36186 av_free(picture->data);
philpem@5 36187 av_free(picture);
philpem@5 36188 av_free(tmp_pict->data[0]);
philpem@5 36189 av_free(tmp_pict);
philpem@5 36190 avcodec_close(video_str->codec);
philpem@5 36191 av_free(oc);
philpem@5 36192 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%', failed to get conversion context.",
philpem@5 36193 pixel_type(),filename);
philpem@5 36194 }
philpem@5 36195 int ret = 0, out_size;
philpem@5 36196 uint8_t *video_outbuf = 0;
philpem@5 36197 int video_outbuf_size = 1000000;
philpem@5 36198 video_outbuf = (uint8_t*)av_malloc(video_outbuf_size);
philpem@5 36199 if (!video_outbuf) {
philpem@5 36200 // if (!(fmt->flags & AVFMT_NOFILE)) url_fclose(&oc->pb);
philpem@5 36201 av_free(picture->data);
philpem@5 36202 av_free(picture);
philpem@5 36203 av_free(tmp_pict->data[0]);
philpem@5 36204 av_free(tmp_pict);
philpem@5 36205 avcodec_close(video_str->codec);
philpem@5 36206 av_free(oc);
philpem@5 36207 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', memory allocation error.",
philpem@5 36208 pixel_type(),filename);
philpem@5 36209 }
philpem@5 36210
philpem@5 36211 // Loop through each desired image in list.
philpem@5 36212 for (unsigned int i = first_frame; i<=nlast_frame; ++i) {
philpem@5 36213 CImg<uint8_t> currentIm = data[i], red, green, blue, gray;
philpem@5 36214 if (src_pxl_fmt == PIX_FMT_RGB24) {
philpem@5 36215 red = currentIm.get_shared_channel(0);
philpem@5 36216 green = currentIm.get_shared_channel(1);
philpem@5 36217 blue = currentIm.get_shared_channel(2);
philpem@5 36218 cimg_forXY(currentIm,X,Y) { // Assign pizel values to data buffer in interlaced RGBRGB ... format.
philpem@5 36219 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X] = red(X,Y);
philpem@5 36220 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 1] = green(X,Y);
philpem@5 36221 tmp_pict->data[0][Y*tmp_pict->linesize[0] + 3*X + 2] = blue(X,Y);
philpem@5 36222 }
philpem@5 36223 } else {
philpem@5 36224 gray = currentIm.get_shared_channel(0);
philpem@5 36225 cimg_forXY(currentIm,X,Y) tmp_pict->data[0][Y*tmp_pict->linesize[0] + X] = gray(X,Y);
philpem@5 36226 }
philpem@5 36227
philpem@5 36228 if (video_str) video_pts = (video_str->pts.val * video_str->time_base.num)/(video_str->time_base.den);
philpem@5 36229 else video_pts = 0.0;
philpem@5 36230 if (!video_str) break;
philpem@5 36231 if (sws_scale(img_convert_context,tmp_pict->data,tmp_pict->linesize,0,c->height,picture->data,picture->linesize)<0) break;
philpem@5 36232 out_size = avcodec_encode_video(c,video_outbuf,video_outbuf_size,picture);
philpem@5 36233 if (out_size>0) {
philpem@5 36234 AVPacket pkt;
philpem@5 36235 av_init_packet(&pkt);
philpem@5 36236 pkt.pts = av_rescale_q(c->coded_frame->pts,c->time_base,video_str->time_base);
philpem@5 36237 if (c->coded_frame->key_frame) pkt.flags|=PKT_FLAG_KEY;
philpem@5 36238 pkt.stream_index = video_str->index;
philpem@5 36239 pkt.data = video_outbuf;
philpem@5 36240 pkt.size = out_size;
philpem@5 36241 ret = av_write_frame(oc,&pkt);
philpem@5 36242 } else if (out_size<0) break;
philpem@5 36243 if (ret) break; // Error occured in writing frame.
philpem@5 36244 }
philpem@5 36245
philpem@5 36246 // Close codec.
philpem@5 36247 if (video_str) {
philpem@5 36248 avcodec_close(video_str->codec);
philpem@5 36249 av_free(picture->data[0]);
philpem@5 36250 av_free(picture);
philpem@5 36251 av_free(tmp_pict->data[0]);
philpem@5 36252 av_free(tmp_pict);
philpem@5 36253 }
philpem@5 36254 if (av_write_trailer(oc)<0)
philpem@5 36255 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to write trailer.",
philpem@5 36256 pixel_type(),filename);
philpem@5 36257 av_freep(&oc->streams[stream_index]->codec);
philpem@5 36258 av_freep(&oc->streams[stream_index]);
philpem@5 36259 if (!(fmt->flags&AVFMT_NOFILE)) {
philpem@5 36260 /*if (url_fclose(oc->pb)<0)
philpem@5 36261 throw CImgIOException("CImgList<%s>::save_ffmpeg() : File '%s', failed to close file.",
philpem@5 36262 pixel_type(),filename);
philpem@5 36263 */
philpem@5 36264 }
philpem@5 36265 av_free(oc);
philpem@5 36266 av_free(video_outbuf);
philpem@5 36267 #endif
philpem@5 36268 return *this;
philpem@5 36269 }
philpem@5 36270
philpem@5 36271 // Save an image sequence into a YUV file (internal).
philpem@5 36272 const CImgList<T>& _save_yuv(cimg_std::FILE *const file, const char *const filename, const bool rgb2yuv) const {
philpem@5 36273 if (is_empty())
philpem@5 36274 throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36275 pixel_type(),filename?filename:"(FILE*)",size,data);
philpem@5 36276 if (!file && !filename)
philpem@5 36277 throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).",
philpem@5 36278 pixel_type(),size,data);
philpem@5 36279 if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2)
philpem@5 36280 throw CImgInstanceException("CImgList<%s>::save_yuv() : File '%s', image dimensions must be even numbers (current are %ux%u).",
philpem@5 36281 pixel_type(),filename?filename:"(FILE*)",(*this)[0].dimx(),(*this)[0].dimy());
philpem@5 36282
philpem@5 36283 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 36284 cimglist_for(*this,l) {
philpem@5 36285 CImg<ucharT> YCbCr((*this)[l]);
philpem@5 36286 if (rgb2yuv) YCbCr.RGBtoYCbCr();
philpem@5 36287 cimg::fwrite(YCbCr.data,YCbCr.width*YCbCr.height,nfile);
philpem@5 36288 cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1),
philpem@5 36289 YCbCr.width*YCbCr.height/2,nfile);
philpem@5 36290 }
philpem@5 36291 if (!file) cimg::fclose(nfile);
philpem@5 36292 return *this;
philpem@5 36293 }
philpem@5 36294
philpem@5 36295 //! Save an image sequence into a YUV file.
philpem@5 36296 const CImgList<T>& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const {
philpem@5 36297 return _save_yuv(0,filename,rgb2yuv);
philpem@5 36298 }
philpem@5 36299
philpem@5 36300 //! Save an image sequence into a YUV file.
philpem@5 36301 const CImgList<T>& save_yuv(cimg_std::FILE *const file, const bool rgb2yuv=true) const {
philpem@5 36302 return _save_yuv(file,0,rgb2yuv);
philpem@5 36303 }
philpem@5 36304
philpem@5 36305 //! Save an image list into a .cimg file.
philpem@5 36306 /**
philpem@5 36307 A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg<T> images.
philpem@5 36308 \param filename : name of the output file.
philpem@5 36309 \return A reference to the current CImgList instance is returned.
philpem@5 36310 **/
philpem@5 36311 const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename, const bool compression) const {
philpem@5 36312 if (is_empty())
philpem@5 36313 throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36314 pixel_type(),filename?filename:"(FILE*)",size,data);
philpem@5 36315 if (!file && !filename)
philpem@5 36316 throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
philpem@5 36317 pixel_type(),size,data);
philpem@5 36318 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 36319 const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little";
philpem@5 36320 if (cimg_std::strstr(ptype,"unsigned")==ptype) cimg_std::fprintf(nfile,"%u unsigned_%s %s_endian\n",size,ptype+9,etype);
philpem@5 36321 else cimg_std::fprintf(nfile,"%u %s %s_endian\n",size,ptype,etype);
philpem@5 36322 cimglist_for(*this,l) {
philpem@5 36323 const CImg<T>& img = data[l];
philpem@5 36324 cimg_std::fprintf(nfile,"%u %u %u %u",img.width,img.height,img.depth,img.dim);
philpem@5 36325 if (img.data) {
philpem@5 36326 CImg<T> tmp;
philpem@5 36327 if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp.data,tmp.size()); }
philpem@5 36328 const CImg<T>& ref = cimg::endianness()?tmp:img;
philpem@5 36329 bool compressed = false;
philpem@5 36330 if (compression) {
philpem@5 36331 #ifdef cimg_use_zlib
philpem@5 36332 const unsigned long siz = sizeof(T)*ref.size();
philpem@5 36333 unsigned long csiz = siz + siz/10 + 16;
philpem@5 36334 Bytef *const cbuf = new Bytef[csiz];
philpem@5 36335 if (compress(cbuf,&csiz,(Bytef*)ref.data,siz)) {
philpem@5 36336 cimg::warn("CImgList<%s>::save_cimg() : File '%s', failed to save compressed data.\n Data will be saved uncompressed.",
philpem@5 36337 pixel_type(),filename?filename:"(FILE*)");
philpem@5 36338 compressed = false;
philpem@5 36339 } else {
philpem@5 36340 cimg_std::fprintf(nfile," #%lu\n",csiz);
philpem@5 36341 cimg::fwrite(cbuf,csiz,nfile);
philpem@5 36342 delete[] cbuf;
philpem@5 36343 compressed = true;
philpem@5 36344 }
philpem@5 36345 #else
philpem@5 36346 cimg::warn("CImgList<%s>::save_cimg() : File '%s', cannot save compressed data unless zlib is used "
philpem@5 36347 "('cimg_use_zlib' must be defined).\n Data will be saved uncompressed.",
philpem@5 36348 pixel_type(),filename?filename:"(FILE*)");
philpem@5 36349 compressed = false;
philpem@5 36350 #endif
philpem@5 36351 }
philpem@5 36352 if (!compressed) {
philpem@5 36353 cimg_std::fputc('\n',nfile);
philpem@5 36354 cimg::fwrite(ref.data,ref.size(),nfile);
philpem@5 36355 }
philpem@5 36356 } else cimg_std::fputc('\n',nfile);
philpem@5 36357 }
philpem@5 36358 if (!file) cimg::fclose(nfile);
philpem@5 36359 return *this;
philpem@5 36360 }
philpem@5 36361
philpem@5 36362 //! Save an image list into a CImg file (RAW binary file + simple header)
philpem@5 36363 const CImgList<T>& save_cimg(cimg_std::FILE *file, const bool compress=false) const {
philpem@5 36364 return _save_cimg(file,0,compress);
philpem@5 36365 }
philpem@5 36366
philpem@5 36367 //! Save an image list into a CImg file (RAW binary file + simple header)
philpem@5 36368 const CImgList<T>& save_cimg(const char *const filename, const bool compress=false) const {
philpem@5 36369 return _save_cimg(0,filename,compress);
philpem@5 36370 }
philpem@5 36371
philpem@5 36372 // Insert the instance image into into an existing .cimg file, at specified coordinates.
philpem@5 36373 const CImgList<T>& _save_cimg(cimg_std::FILE *const file, const char *const filename,
philpem@5 36374 const unsigned int n0,
philpem@5 36375 const unsigned int x0, const unsigned int y0,
philpem@5 36376 const unsigned int z0, const unsigned int v0) const {
philpem@5 36377 #define _cimg_save_cimg_case(Ts,Tss) \
philpem@5 36378 if (!saved && !cimg::strcasecmp(Ts,str_pixeltype)) { \
philpem@5 36379 for (unsigned int l=0; l<lmax; ++l) { \
philpem@5 36380 j = 0; while((i=cimg_std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \
philpem@5 36381 W = H = D = V = 0; \
philpem@5 36382 if (cimg_std::sscanf(tmp,"%u %u %u %u",&W,&H,&D,&V)!=4) \
philpem@5 36383 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Image %u has an invalid size (%u,%u,%u,%u)\n", \
philpem@5 36384 pixel_type(), filename?filename:("(FILE*)"), W, H, D, V); \
philpem@5 36385 if (W*H*D*V>0) { \
philpem@5 36386 if (l<n0 || x0>=W || y0>=H || z0>=D || v0>=D) cimg_std::fseek(nfile,W*H*D*V*sizeof(Tss),SEEK_CUR); \
philpem@5 36387 else { \
philpem@5 36388 const CImg<T>& img = (*this)[l-n0]; \
philpem@5 36389 const T *ptrs = img.data; \
philpem@5 36390 const unsigned int \
philpem@5 36391 x1 = x0 + img.width - 1, \
philpem@5 36392 y1 = y0 + img.height - 1, \
philpem@5 36393 z1 = z0 + img.depth - 1, \
philpem@5 36394 v1 = v0 + img.dim - 1, \
philpem@5 36395 nx1 = x1>=W?W-1:x1, \
philpem@5 36396 ny1 = y1>=H?H-1:y1, \
philpem@5 36397 nz1 = z1>=D?D-1:z1, \
philpem@5 36398 nv1 = v1>=V?V-1:v1; \
philpem@5 36399 CImg<Tss> raw(1+nx1-x0); \
philpem@5 36400 const unsigned int skipvb = v0*W*H*D*sizeof(Tss); \
philpem@5 36401 if (skipvb) cimg_std::fseek(nfile,skipvb,SEEK_CUR); \
philpem@5 36402 for (unsigned int v=1+nv1-v0; v; --v) { \
philpem@5 36403 const unsigned int skipzb = z0*W*H*sizeof(Tss); \
philpem@5 36404 if (skipzb) cimg_std::fseek(nfile,skipzb,SEEK_CUR); \
philpem@5 36405 for (unsigned int z=1+nz1-z0; z; --z) { \
philpem@5 36406 const unsigned int skipyb = y0*W*sizeof(Tss); \
philpem@5 36407 if (skipyb) cimg_std::fseek(nfile,skipyb,SEEK_CUR); \
philpem@5 36408 for (unsigned int y=1+ny1-y0; y; --y) { \
philpem@5 36409 const unsigned int skipxb = x0*sizeof(Tss); \
philpem@5 36410 if (skipxb) cimg_std::fseek(nfile,skipxb,SEEK_CUR); \
philpem@5 36411 raw.assign(ptrs, raw.width); \
philpem@5 36412 ptrs+=img.width; \
philpem@5 36413 if (endian) cimg::invert_endianness(raw.data,raw.width); \
philpem@5 36414 cimg::fwrite(raw.data,raw.width,nfile); \
philpem@5 36415 const unsigned int skipxe = (W-1-nx1)*sizeof(Tss); \
philpem@5 36416 if (skipxe) cimg_std::fseek(nfile,skipxe,SEEK_CUR); \
philpem@5 36417 } \
philpem@5 36418 const unsigned int skipye = (H-1-ny1)*W*sizeof(Tss); \
philpem@5 36419 if (skipye) cimg_std::fseek(nfile,skipye,SEEK_CUR); \
philpem@5 36420 } \
philpem@5 36421 const unsigned int skipze = (D-1-nz1)*W*H*sizeof(Tss); \
philpem@5 36422 if (skipze) cimg_std::fseek(nfile,skipze,SEEK_CUR); \
philpem@5 36423 } \
philpem@5 36424 const unsigned int skipve = (V-1-nv1)*W*H*D*sizeof(Tss); \
philpem@5 36425 if (skipve) cimg_std::fseek(nfile,skipve,SEEK_CUR); \
philpem@5 36426 } \
philpem@5 36427 } \
philpem@5 36428 } \
philpem@5 36429 saved = true; \
philpem@5 36430 }
philpem@5 36431 if (is_empty())
philpem@5 36432 throw CImgInstanceException("CImgList<%s>::save_cimg() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36433 pixel_type(),filename?filename:"(FILE*)",size,data);
philpem@5 36434 if (!file && !filename)
philpem@5 36435 throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).",
philpem@5 36436 pixel_type(),size,data);
philpem@5 36437 typedef unsigned char uchar;
philpem@5 36438 typedef unsigned short ushort;
philpem@5 36439 typedef unsigned int uint;
philpem@5 36440 typedef unsigned long ulong;
philpem@5 36441 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+");
philpem@5 36442 bool saved = false, endian = cimg::endianness();
philpem@5 36443 char tmp[256], str_pixeltype[256], str_endian[256];
philpem@5 36444 unsigned int j, err, N, W, H, D, V;
philpem@5 36445 int i;
philpem@5 36446 j = 0; while((i=cimg_std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = '\0';
philpem@5 36447 err = cimg_std::sscanf(tmp,"%u%*c%255[A-Za-z_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype,str_endian);
philpem@5 36448 if (err<2) {
philpem@5 36449 if (!file) cimg::fclose(nfile);
philpem@5 36450 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', Unknow CImg RAW header.",
philpem@5 36451 pixel_type(),filename?filename:"(FILE*)");
philpem@5 36452 }
philpem@5 36453 if (!cimg::strncasecmp("little",str_endian,6)) endian = false;
philpem@5 36454 else if (!cimg::strncasecmp("big",str_endian,3)) endian = true;
philpem@5 36455 const unsigned int lmax = cimg::min(N,n0+size);
philpem@5 36456 _cimg_save_cimg_case("bool",bool);
philpem@5 36457 _cimg_save_cimg_case("unsigned_char",uchar);
philpem@5 36458 _cimg_save_cimg_case("uchar",uchar);
philpem@5 36459 _cimg_save_cimg_case("char",char);
philpem@5 36460 _cimg_save_cimg_case("unsigned_short",ushort);
philpem@5 36461 _cimg_save_cimg_case("ushort",ushort);
philpem@5 36462 _cimg_save_cimg_case("short",short);
philpem@5 36463 _cimg_save_cimg_case("unsigned_int",uint);
philpem@5 36464 _cimg_save_cimg_case("uint",uint);
philpem@5 36465 _cimg_save_cimg_case("int",int);
philpem@5 36466 _cimg_save_cimg_case("unsigned_long",ulong);
philpem@5 36467 _cimg_save_cimg_case("ulong",ulong);
philpem@5 36468 _cimg_save_cimg_case("long",long);
philpem@5 36469 _cimg_save_cimg_case("float",float);
philpem@5 36470 _cimg_save_cimg_case("double",double);
philpem@5 36471 if (!saved) {
philpem@5 36472 if (!file) cimg::fclose(nfile);
philpem@5 36473 throw CImgIOException("CImgList<%s>::save_cimg() : File '%s', cannot save images of pixels coded as '%s'.",
philpem@5 36474 pixel_type(),filename?filename:"(FILE*)",str_pixeltype);
philpem@5 36475 }
philpem@5 36476 if (!file) cimg::fclose(nfile);
philpem@5 36477 return *this;
philpem@5 36478 }
philpem@5 36479
philpem@5 36480 //! Insert the instance image into into an existing .cimg file, at specified coordinates.
philpem@5 36481 const CImgList<T>& save_cimg(const char *const filename,
philpem@5 36482 const unsigned int n0,
philpem@5 36483 const unsigned int x0, const unsigned int y0,
philpem@5 36484 const unsigned int z0, const unsigned int v0) const {
philpem@5 36485 return _save_cimg(0,filename,n0,x0,y0,z0,v0);
philpem@5 36486 }
philpem@5 36487
philpem@5 36488 //! Insert the instance image into into an existing .cimg file, at specified coordinates.
philpem@5 36489 const CImgList<T>& save_cimg(cimg_std::FILE *const file,
philpem@5 36490 const unsigned int n0,
philpem@5 36491 const unsigned int x0, const unsigned int y0,
philpem@5 36492 const unsigned int z0, const unsigned int v0) const {
philpem@5 36493 return _save_cimg(file,0,n0,x0,y0,z0,v0);
philpem@5 36494 }
philpem@5 36495
philpem@5 36496 // Create an empty .cimg file with specified dimensions (internal)
philpem@5 36497 static void _save_empty_cimg(cimg_std::FILE *const file, const char *const filename,
philpem@5 36498 const unsigned int nb,
philpem@5 36499 const unsigned int dx, const unsigned int dy,
philpem@5 36500 const unsigned int dz, const unsigned int dv) {
philpem@5 36501 cimg_std::FILE *const nfile = file?file:cimg::fopen(filename,"wb");
philpem@5 36502 const unsigned int siz = dx*dy*dz*dv*sizeof(T);
philpem@5 36503 cimg_std::fprintf(nfile,"%u %s\n",nb,pixel_type());
philpem@5 36504 for (unsigned int i=nb; i; --i) {
philpem@5 36505 cimg_std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dv);
philpem@5 36506 for (unsigned int off=siz; off; --off) cimg_std::fputc(0,nfile);
philpem@5 36507 }
philpem@5 36508 if (!file) cimg::fclose(nfile);
philpem@5 36509 }
philpem@5 36510
philpem@5 36511 //! Create an empty .cimg file with specified dimensions.
philpem@5 36512 static void save_empty_cimg(const char *const filename,
philpem@5 36513 const unsigned int nb,
philpem@5 36514 const unsigned int dx, const unsigned int dy=1,
philpem@5 36515 const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 36516 return _save_empty_cimg(0,filename,nb,dx,dy,dz,dv);
philpem@5 36517 }
philpem@5 36518
philpem@5 36519 //! Create an empty .cimg file with specified dimensions.
philpem@5 36520 static void save_empty_cimg(cimg_std::FILE *const file,
philpem@5 36521 const unsigned int nb,
philpem@5 36522 const unsigned int dx, const unsigned int dy=1,
philpem@5 36523 const unsigned int dz=1, const unsigned int dv=1) {
philpem@5 36524 return _save_empty_cimg(file,0,nb,dx,dy,dz,dv);
philpem@5 36525 }
philpem@5 36526
philpem@5 36527 //! Save a file in TIFF format.
philpem@5 36528 #ifdef cimg_use_tiff
philpem@5 36529 const CImgList<T>& save_tiff(const char *const filename) const {
philpem@5 36530 if (is_empty())
philpem@5 36531 throw CImgInstanceException("CImgList<%s>::save_tiff() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36532 pixel_type(),filename?filename:"(null)",size,data);
philpem@5 36533 if (!filename)
philpem@5 36534 throw CImgArgumentException("CImgList<%s>::save_tiff() : Specified filename is (null) for instance list (%u,%p).",
philpem@5 36535 pixel_type(),size,data);
philpem@5 36536 TIFF *tif = TIFFOpen(filename,"w");
philpem@5 36537 if (tif) {
philpem@5 36538 for (unsigned int dir=0, l=0; l<size; ++l) {
philpem@5 36539 const CImg<T>& img = (*this)[l];
philpem@5 36540 if (img) {
philpem@5 36541 if (img.depth==1) img._save_tiff(tif,dir++);
philpem@5 36542 else cimg_forZ(img,z) img.get_slice(z)._save_tiff(tif,dir++);
philpem@5 36543 }
philpem@5 36544 }
philpem@5 36545 TIFFClose(tif);
philpem@5 36546 } else
philpem@5 36547 throw CImgException("CImgList<%s>::save_tiff() : File '%s', error while opening stream for tiff file.",
philpem@5 36548 pixel_type(),filename);
philpem@5 36549 return *this;
philpem@5 36550 }
philpem@5 36551 #endif
philpem@5 36552
philpem@5 36553 //! Save an image list as a gzipped file, using external tool 'gzip'.
philpem@5 36554 const CImgList<T>& save_gzip_external(const char *const filename) const {
philpem@5 36555 if (!filename)
philpem@5 36556 throw CImgIOException("CImg<%s>::save_gzip_external() : Cannot save (null) filename.",
philpem@5 36557 pixel_type());
philpem@5 36558 char command[1024], filetmp[512], body[512];
philpem@5 36559 const char
philpem@5 36560 *ext = cimg::split_filename(filename,body),
philpem@5 36561 *ext2 = cimg::split_filename(body,0);
philpem@5 36562 cimg_std::FILE *file;
philpem@5 36563 do {
philpem@5 36564 if (!cimg::strcasecmp(ext,"gz")) {
philpem@5 36565 if (*ext2) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 36566 cimg::filenamerand(),ext2);
philpem@5 36567 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 36568 cimg::filenamerand());
philpem@5 36569 } else {
philpem@5 36570 if (*ext) cimg_std::sprintf(filetmp,"%s%s%s.%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 36571 cimg::filenamerand(),ext);
philpem@5 36572 else cimg_std::sprintf(filetmp,"%s%s%s.cimg",cimg::temporary_path(),cimg_OS==2?"\\":"/",
philpem@5 36573 cimg::filenamerand());
philpem@5 36574 }
philpem@5 36575 if ((file=cimg_std::fopen(filetmp,"rb"))!=0) cimg_std::fclose(file);
philpem@5 36576 } while (file);
philpem@5 36577 save(filetmp);
philpem@5 36578 cimg_std::sprintf(command,"%s -c %s > \"%s\"",cimg::gzip_path(),filetmp,filename);
philpem@5 36579 cimg::system(command);
philpem@5 36580 file = cimg_std::fopen(filename,"rb");
philpem@5 36581 if (!file)
philpem@5 36582 throw CImgIOException("CImgList<%s>::save_gzip_external() : File '%s' cannot be saved.",
philpem@5 36583 pixel_type(),filename);
philpem@5 36584 else cimg::fclose(file);
philpem@5 36585 cimg_std::remove(filetmp);
philpem@5 36586 return *this;
philpem@5 36587 }
philpem@5 36588
philpem@5 36589 //! Save an image list into a OFF file.
philpem@5 36590 template<typename tf, typename tc>
philpem@5 36591 const CImgList<T>& save_off(const char *const filename,
philpem@5 36592 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
philpem@5 36593 get_append('x','y').save_off(filename,primitives,colors,invert_faces);
philpem@5 36594 return *this;
philpem@5 36595 }
philpem@5 36596
philpem@5 36597 //! Save an image list into a OFF file.
philpem@5 36598 template<typename tf, typename tc>
philpem@5 36599 const CImgList<T>& save_off(cimg_std::FILE *const file,
philpem@5 36600 const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const {
philpem@5 36601 get_append('x','y').save_off(file,primitives,colors,invert_faces);
philpem@5 36602 return *this;
philpem@5 36603 }
philpem@5 36604
philpem@5 36605 //! Save an image sequence using the external tool 'ffmpeg'.
philpem@5 36606 const CImgList<T>& save_ffmpeg_external(const char *const filename, const unsigned int first_frame=0, const unsigned int last_frame=~0U,
philpem@5 36607 const char *const codec="mpeg2video") const {
philpem@5 36608 if (is_empty())
philpem@5 36609 throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', instance list (%u,%p) is empty.",
philpem@5 36610 pixel_type(),filename?filename:"(null)",size,data);
philpem@5 36611 if (!filename)
philpem@5 36612 throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : Instance list (%u,%p), specified filename is (null).",
philpem@5 36613 pixel_type(),size,data);
philpem@5 36614 char command[1024], filetmp[512], filetmp2[512];
philpem@5 36615 cimg_std::FILE *file = 0;
philpem@5 36616 const unsigned int nlast_frame = last_frame==~0U?size-1:last_frame;
philpem@5 36617 if (first_frame>=size || nlast_frame>=size)
philpem@5 36618 throw CImgArgumentException("CImgList<%s>::save_ffmpeg_external() : File '%s', specified frames [%u,%u] are out of list range (%u elements).",
philpem@5 36619 pixel_type(),filename,first_frame,last_frame,size);
philpem@5 36620 for (unsigned int ll = first_frame; ll<=nlast_frame; ++ll) if (!data[ll].is_sameXYZ(data[0]))
philpem@5 36621 throw CImgInstanceException("CImgList<%s>::save_ffmpeg_external() : File '%s', all images of the sequence must be of the same dimension.",
philpem@5 36622 pixel_type(),filename);
philpem@5 36623 do {
philpem@5 36624 cimg_std::sprintf(filetmp,"%s%s%s",cimg::temporary_path(),cimg_OS==2?"\\":"/",cimg::filenamerand());
philpem@5 36625 cimg_std::sprintf(filetmp2,"%s_000001.ppm",filetmp);
philpem@5 36626 if ((file=cimg_std::fopen(filetmp2,"rb"))!=0) cimg_std::fclose(file);
philpem@5 36627 } while (file);
philpem@5 36628 for (unsigned int l = first_frame; l<=nlast_frame; ++l) {
philpem@5 36629 cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,l+1);
philpem@5 36630 if (data[l].depth>1 || data[l].dim!=3) data[l].get_resize(-100,-100,1,3).save_pnm(filetmp2);
philpem@5 36631 else data[l].save_pnm(filetmp2);
philpem@5 36632 }
philpem@5 36633 #if cimg_OS!=2
philpem@5 36634 cimg_std::sprintf(command,"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\" >/dev/null 2>&1",filetmp,codec,filename);
philpem@5 36635 #else
philpem@5 36636 cimg_std::sprintf(command,"\"ffmpeg -i %s_%%6d.ppm -vcodec %s -sameq -y \"%s\"\" >NUL 2>&1",filetmp,codec,filename);
philpem@5 36637 #endif
philpem@5 36638 cimg::system(command);
philpem@5 36639 file = cimg_std::fopen(filename,"rb");
philpem@5 36640 if (!file)
philpem@5 36641 throw CImgIOException("CImg<%s>::save_ffmpeg_external() : Failed to save image sequence '%s'.\n\n",
philpem@5 36642 pixel_type(),filename);
philpem@5 36643 else cimg::fclose(file);
philpem@5 36644 cimglist_for(*this,lll) { cimg_std::sprintf(filetmp2,"%s_%.6u.ppm",filetmp,lll+1); cimg_std::remove(filetmp2); }
philpem@5 36645 return *this;
philpem@5 36646 }
philpem@5 36647
philpem@5 36648 };
philpem@5 36649
philpem@5 36650 /*
philpem@5 36651 #---------------------------------------------
philpem@5 36652 #
philpem@5 36653 # Completion of previously declared functions
philpem@5 36654 #
philpem@5 36655 #----------------------------------------------
philpem@5 36656 */
philpem@5 36657
philpem@5 36658 namespace cimg {
philpem@5 36659
philpem@5 36660 //! Display a dialog box, where a user can click standard buttons.
philpem@5 36661 /**
philpem@5 36662 Up to 6 buttons can be defined in the dialog window.
philpem@5 36663 This function returns when a user clicked one of the button or closed the dialog window.
philpem@5 36664 \param title = Title of the dialog window.
philpem@5 36665 \param msg = Main message displayed inside the dialog window.
philpem@5 36666 \param button1_txt = Label of the 1st button.
philpem@5 36667 \param button2_txt = Label of the 2nd button.
philpem@5 36668 \param button3_txt = Label of the 3rd button.
philpem@5 36669 \param button4_txt = Label of the 4th button.
philpem@5 36670 \param button5_txt = Label of the 5th button.
philpem@5 36671 \param button6_txt = Label of the 6th button.
philpem@5 36672 \param logo = Logo image displayed at the left of the main message. This parameter is optional.
philpem@5 36673 \param centering = Tell to center the dialog window on the screen.
philpem@5 36674 \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user.
philpem@5 36675 \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in
philpem@5 36676 the dialog box. At least one button is necessary.
philpem@5 36677 **/
philpem@5 36678
philpem@5 36679 template<typename t>
philpem@5 36680 inline int dialog(const char *title, const char *msg,
philpem@5 36681 const char *button1_txt, const char *button2_txt,
philpem@5 36682 const char *button3_txt, const char *button4_txt,
philpem@5 36683 const char *button5_txt, const char *button6_txt,
philpem@5 36684 const CImg<t>& logo, const bool centering = false) {
philpem@5 36685 #if cimg_display!=0
philpem@5 36686 const unsigned char
philpem@5 36687 black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };
philpem@5 36688
philpem@5 36689 // Create buttons and canvas graphics
philpem@5 36690 CImgList<unsigned char> buttons, cbuttons, sbuttons;
philpem@5 36691 if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button1_txt,black,gray,1,13));
philpem@5 36692 if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button2_txt,black,gray,1,13));
philpem@5 36693 if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button3_txt,black,gray,1,13));
philpem@5 36694 if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button4_txt,black,gray,1,13));
philpem@5 36695 if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button5_txt,black,gray,1,13));
philpem@5 36696 if (button6_txt) { buttons.insert(CImg<unsigned char>().draw_text(0,0,button6_txt,black,gray,1,13));
philpem@5 36697 }}}}}}
philpem@5 36698 if (!buttons.size)
philpem@5 36699 throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary");
philpem@5 36700
philpem@5 36701 unsigned int bw = 0, bh = 0;
philpem@5 36702 cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); }
philpem@5 36703 bw+=8; bh+=8;
philpem@5 36704 if (bw<64) bw=64;
philpem@5 36705 if (bw>128) bw=128;
philpem@5 36706 if (bh<24) bh=24;
philpem@5 36707 if (bh>48) bh=48;
philpem@5 36708
philpem@5 36709 CImg<unsigned char> button(bw,bh,1,3);
philpem@5 36710 button.draw_rectangle(0,0,bw-1,bh-1,gray);
philpem@5 36711 button.draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white);
philpem@5 36712 button.draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black);
philpem@5 36713 button.draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2);
philpem@5 36714 CImg<unsigned char> sbutton(bw,bh,1,3);
philpem@5 36715 sbutton.draw_rectangle(0,0,bw-1,bh-1,gray);
philpem@5 36716 sbutton.draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black);
philpem@5 36717 sbutton.draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black);
philpem@5 36718 sbutton.draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white);
philpem@5 36719 sbutton.draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black);
philpem@5 36720 sbutton.draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2);
philpem@5 36721 sbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
philpem@5 36722 sbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
philpem@5 36723 CImg<unsigned char> cbutton(bw,bh,1,3);
philpem@5 36724 cbutton.draw_rectangle(0,0,bw-1,bh-1,black).draw_rectangle(1,1,bw-2,bh-2,gray2).draw_rectangle(2,2,bw-3,bh-3,gray);
philpem@5 36725 cbutton.draw_line(4,4,bw-5,4,black,1,0xAAAAAAAA,true).draw_line(bw-5,4,bw-5,bh-5,black,1,0xAAAAAAAA,false);
philpem@5 36726 cbutton.draw_line(bw-5,bh-5,4,bh-5,black,1,0xAAAAAAAA,false).draw_line(4,bh-5,4,4,black,1,0xAAAAAAAA,false);
philpem@5 36727
philpem@5 36728 cimglist_for(buttons,ll) {
philpem@5 36729 cbuttons.insert(CImg<unsigned char>(cbutton).draw_image(1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2,buttons[ll]));
philpem@5 36730 sbuttons.insert(CImg<unsigned char>(sbutton).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]));
philpem@5 36731 buttons[ll] = CImg<unsigned char>(button).draw_image((bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2,buttons[ll]);
philpem@5 36732 }
philpem@5 36733
philpem@5 36734 CImg<unsigned char> canvas;
philpem@5 36735 if (msg) canvas = CImg<unsigned char>().draw_text(0,0,msg,black,gray,1,13);
philpem@5 36736 const unsigned int
philpem@5 36737 bwall = (buttons.size-1)*(12+bw) + bw,
philpem@5 36738 w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall),
philpem@5 36739 h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh),
philpem@5 36740 lx = 12 + (canvas.data?0:((w-24-logo.width)/2)),
philpem@5 36741 ly = (h-12-bh-logo.height)/2,
philpem@5 36742 tx = lx+logo.width+12,
philpem@5 36743 ty = (h-12-bh-canvas.height)/2,
philpem@5 36744 bx = (w-bwall)/2,
philpem@5 36745 by = h-12-bh;
philpem@5 36746
philpem@5 36747 if (canvas.data)
philpem@5 36748 canvas = CImg<unsigned char>(w,h,1,3).
philpem@5 36749 draw_rectangle(0,0,w-1,h-1,gray).
philpem@5 36750 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
philpem@5 36751 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black).
philpem@5 36752 draw_image(tx,ty,canvas);
philpem@5 36753 else
philpem@5 36754 canvas = CImg<unsigned char>(w,h,1,3).
philpem@5 36755 draw_rectangle(0,0,w-1,h-1,gray).
philpem@5 36756 draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white).
philpem@5 36757 draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black);
philpem@5 36758 if (logo.data) canvas.draw_image(lx,ly,logo);
philpem@5 36759
philpem@5 36760 unsigned int xbuttons[6];
philpem@5 36761 cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(xbuttons[lll],by,buttons[lll]); }
philpem@5 36762
philpem@5 36763 // Open window and enter events loop
philpem@5 36764 CImgDisplay disp(canvas,title?title:" ",0,false,centering?true:false);
philpem@5 36765 if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2,
philpem@5 36766 (CImgDisplay::screen_dimy()-disp.dimy())/2);
philpem@5 36767 bool stopflag = false, refresh = false;
philpem@5 36768 int oselected = -1, oclicked = -1, selected = -1, clicked = -1;
philpem@5 36769 while (!disp.is_closed && !stopflag) {
philpem@5 36770 if (refresh) {
philpem@5 36771 if (clicked>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp);
philpem@5 36772 else {
philpem@5 36773 if (selected>=0) CImg<unsigned char>(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp);
philpem@5 36774 else canvas.display(disp);
philpem@5 36775 }
philpem@5 36776 refresh = false;
philpem@5 36777 }
philpem@5 36778 disp.wait(15);
philpem@5 36779 if (disp.is_resized) disp.resize(disp);
philpem@5 36780
philpem@5 36781 if (disp.button&1) {
philpem@5 36782 oclicked = clicked;
philpem@5 36783 clicked = -1;
philpem@5 36784 cimglist_for(buttons,l)
philpem@5 36785 if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) &&
philpem@5 36786 disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) {
philpem@5 36787 clicked = selected = l;
philpem@5 36788 refresh = true;
philpem@5 36789 }
philpem@5 36790 if (clicked!=oclicked) refresh = true;
philpem@5 36791 } else if (clicked>=0) stopflag = true;
philpem@5 36792
philpem@5 36793 if (disp.key) {
philpem@5 36794 oselected = selected;
philpem@5 36795 switch (disp.key) {
philpem@5 36796 case cimg::keyESC : selected=-1; stopflag=true; break;
philpem@5 36797 case cimg::keyENTER : if (selected<0) selected = 0; stopflag = true; break;
philpem@5 36798 case cimg::keyTAB :
philpem@5 36799 case cimg::keyARROWRIGHT :
philpem@5 36800 case cimg::keyARROWDOWN : selected = (selected+1)%buttons.size; break;
philpem@5 36801 case cimg::keyARROWLEFT :
philpem@5 36802 case cimg::keyARROWUP : selected = (selected+buttons.size-1)%buttons.size; break;
philpem@5 36803 }
philpem@5 36804 disp.key = 0;
philpem@5 36805 if (selected!=oselected) refresh = true;
philpem@5 36806 }
philpem@5 36807 }
philpem@5 36808 if (!disp) selected = -1;
philpem@5 36809 return selected;
philpem@5 36810 #else
philpem@5 36811 cimg_std::fprintf(cimg_stdout,"<%s>\n\n%s\n\n",title,msg);
philpem@5 36812 return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering);
philpem@5 36813 #endif
philpem@5 36814 }
philpem@5 36815
philpem@5 36816 inline int dialog(const char *title, const char *msg,
philpem@5 36817 const char *button1_txt, const char *button2_txt, const char *button3_txt,
philpem@5 36818 const char *button4_txt, const char *button5_txt, const char *button6_txt,
philpem@5 36819 const bool centering) {
philpem@5 36820 return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt,
philpem@5 36821 CImg<unsigned char>::logo40x38(),centering);
philpem@5 36822 }
philpem@5 36823
philpem@5 36824 // End of cimg:: namespace
philpem@5 36825 }
philpem@5 36826
philpem@5 36827 // End of cimg_library:: namespace
philpem@5 36828 }
philpem@5 36829
philpem@5 36830 #ifdef _cimg_redefine_min
philpem@5 36831 #define min(a,b) (((a)<(b))?(a):(b))
philpem@5 36832 #endif
philpem@5 36833 #ifdef _cimg_redefine_max
philpem@5 36834 #define max(a,b) (((a)>(b))?(a):(b))
philpem@5 36835 #endif
philpem@5 36836
philpem@5 36837 #endif
philpem@5 36838 // Local Variables:
philpem@5 36839 // mode: c++
philpem@5 36840 // End: