/* # # File : CImg.h # # Description : The C++ Template Image Processing Library # ( http://cimg.sourceforge.net ) # # Copyright : David Tschumperle # ( http://www.greyc.ensicaen.fr/~dtschump/ ) # # License : CeCILL-C # # This software is governed by the CeCILL-C license under French law and # abiding by the rules of distribution of free software. You can use, # modify and or redistribute the software under the terms of the CeCILL-C # license as circulated by CEA, CNRS and INRIA at the following URL # "http://www.cecill.info". # # As a counterpart to the access to the source code and rights to copy, # modify and redistribute granted by the license, users are provided only # with a limited warranty and the software's author, the holder of the # economic rights, and the successive licensors have only limited # liability. # # In this respect, the user's attention is drawn to the risks associated # with loading, using, modifying and/or developing or reproducing the # software by the user in light of its specific status of free software, # that may mean that it is complicated to manipulate, and that also # therefore means that it is reserved for developers and experienced # professionals having in-depth computer knowledge. Users are therefore # encouraged to load and test the software's suitability as regards their # requirements in conditions enabling the security of their systems and/or # data to be ensured and, more generally, to use and operate it in the # same conditions as regards security. # # The fact that you are presently reading this means that you have had # knowledge of the CeCILL-C license and that you accept its terms. # */ #ifndef cimg_version #define cimg_version 1.22 // Detect Microsoft VC++ 6.0 compiler to get some workarounds afterwards. // (this compiler is a pure shit). #if defined(_MSC_VER) && _MSC_VER<1300 #define cimg_use_visualcpp6 #endif // Avoid strange 'deprecated' warning messages with Visual C++ .NET. #if defined(_MSC_VER) && _MSC_VER>=1300 #define _CRT_SECURE_NO_DEPRECATE 1 #define _CRT_NONSTDC_NO_DEPRECATE 1 #endif // Standard C++ includes. #include #include #include #include #include #include /* # # Set CImg configuration flags. # # If compilation flags are not adapted to your system, # you may override their values, before including # the header file "CImg.h" (use the #define directive). # */ // Try to detect the current system and set value of 'cimg_OS'. #ifndef cimg_OS // Unix-like (Linux, Solaris, BSD, MacOSX, Irix,...). #if defined(unix) || defined(__unix) || defined(__unix__) \ || defined(linux) || defined(__linux) || defined(__linux__) \ || defined(sun) || defined(__sun) \ || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined __DragonFly__ \ || defined(__MACOSX__) || defined(__APPLE__) \ || defined(sgi) || defined(__sgi) \ || defined(__CYGWIN__) #define cimg_OS 1 #ifndef cimg_display_type #define cimg_display_type 1 #endif #ifndef cimg_color_terminal #define cimg_color_terminal #endif // Windows. #elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) #define cimg_OS 2 #ifndef cimg_display_type #define cimg_display_type 2 #endif // Unknown configuration : ask for minimal dependencies (no display). #else #define cimg_OS 0 #ifndef cimg_display_type #define cimg_display_type 0 #endif #endif #endif // Debug configuration. // // Set 'cimg_debug' to : 0 to remove debug messages (exceptions are still thrown anyway). // 1 to display debug messages on standard error output (console). // 2 to display debug messages with modal windows (default behavior). // 3 to do as 2 + add extra memory access warnings (may slow down the code) #ifndef cimg_debug #define cimg_debug 2 #endif // Architecture-dependent includes. #if cimg_OS==1 #include #include #elif cimg_OS==2 #include #ifndef _WIN32_IE #define _WIN32_IE 0x0400 #endif #include #ifdef cimg_use_visualcpp6 #define std #endif #endif // Test if min/max macros are defined, and if so, undef them #ifdef min #undef min #define cimg_redefine_min #endif #ifdef max #undef max #define cimg_redefine_max #endif // Display-dependent includes. #if cimg_display_type==1 #include #include #include #include #ifdef cimg_use_xshm #include #include #include #endif #ifdef cimg_use_xrandr #include #endif #endif // Configuration for using extra libraries // // Define 'cimg_use_png', 'cimg_use_jpeg' or 'cimg_use_tiff' to enable native PNG, JPEG or TIFF files support. // This requires you link your code with the zlib/png, jpeg or tiff libraries. // Without these libraries, PNG,JPEG and TIFF support will be done by the Image Magick's 'convert' tool, // or byt the GraphicsMagick 'gm' tool if installed // (this is the case on most unix plateforms). #ifdef cimg_use_png extern "C" { #include "png.h" } #endif #ifdef cimg_use_jpeg extern "C" { #include "jpeglib.h" } #endif #ifdef cimg_use_tiff extern "C" { #include "tiffio.h" } #endif #ifdef cimg_use_magick #include "Magick++.h" #endif #ifdef cimg_use_fftw3 extern "C" { #include "fftw3.h" } #endif /* # # # Define some useful macros. Macros of the CImg Library are prefixed by 'cimg_' # Documented macros below may be safely used in your own code # (particularly useful for option parsing, image loops and neighborhoods). # # */ // Macros used to describe the program usage, and retrieve command line arguments // (See corresponding module 'Retrieving command line arguments' in the generated documentation). #define cimg_usage(usage) cimg_library::cimg::option((char*)0,argc,argv,(char*)0,usage) #define cimg_help(str) cimg_library::cimg::option((char*)0,argc,argv,str,(char*)0) #define cimg_option(name,defaut,usage) cimg_library::cimg::option(name,argc,argv,defaut,usage) // Macros used for neighborhood definitions and manipulations. // (see module 'Using Image Loops' in the generated documentation). #define CImg_2(I,T) T I##cc,I##nc=0 #define CImg_2x2(I,T) T I##cc,I##nc=0,I##cn,I##nn=0 #define CImg_3(I,T) T I##pp,I##cp,I##np=0 #define CImg_3x3(I,T) T I##pp,I##cp,I##np=0,I##pc,I##cc,I##nc=0,I##pn,I##cn,I##nn=0 #define CImg_4(I,T) T I##pp,I##cp,I##np=0,I##ap=0 #define CImg_4x4(I,T) T I##pp,I##cp,I##np=0,I##ap=0, \ I##pc,I##cc,I##nc=0,I##ac=0, \ I##pn,I##cn,I##nn=0,I##an=0, \ I##pa,I##ca,I##na=0,I##aa=0 #define CImg_5(I,T) T I##bb,I##pb,I##cb,I##nb=0,I##ab=0 #define CImg_5x5(I,T) T I##bb,I##pb,I##cb,I##nb=0,I##ab=0, \ I##bp,I##pp,I##cp,I##np=0,I##ap=0, \ I##bc,I##pc,I##cc,I##nc=0,I##ac=0, \ I##bn,I##pn,I##cn,I##nn=0,I##an=0, \ I##ba,I##pa,I##ca,I##na=0,I##aa=0 #define CImg_2x2x2(I,T) T I##ccc,I##ncc=0,I##cnc,I##nnc=0, \ I##ccn,I##ncn=0,I##cnn,I##nnn=0 #define CImg_3x3x3(I,T) T I##ppp,I##cpp,I##npp=0,I##pcp,I##ccp,I##ncp=0,I##pnp,I##cnp,I##nnp=0, \ I##ppc,I##cpc,I##npc=0,I##pcc,I##ccc,I##ncc=0,I##pnc,I##cnc,I##nnc=0, \ I##ppn,I##cpn,I##npn=0,I##pcn,I##ccn,I##ncn=0,I##pnn,I##cnn,I##nnn=0 #define CImg_2x2_ref(I,T,tab) T &I##cc=(tab)[0],&I##nc=(tab)[1],&I##cn=(tab)[2],&I##nn=(tab)[3] #define CImg_3x3_ref(I,T,tab) T &I##pp=(tab)[0],&I##cp=(tab)[1],&I##np=(tab)[2], \ &I##pc=(tab)[3],&I##cc=(tab)[4],&I##nc=(tab)[5], \ &I##pn=(tab)[6],&I##cn=(tab)[7],&I##nn=(tab)[8] #define CImg_4x4_ref(I,T,tab) T &I##pp=(tab)[0], &I##cp=(tab)[1], &I##np=(tab)[2], &I##ap=(tab)[3], \ &I##pc=(tab)[4], &I##cc=(tab)[5], &I##nc=(tab)[6], &I##ac=(tab)[7], \ &I##pn=(tab)[8], &I##cn=(tab)[9], &I##nn=(tab)[10],&I##an=(tab)[11], \ &I##pa=(tab)[12],&I##ca=(tab)[13],&I##na=(tab)[14],&I##aa=(tab)[15] #define CImg_5x5_ref(I,T,tab) T &I##bb=(tab)[0],&I##pb=(tab)[1],&I##cb=(tab)[2],&I##nb=(tab)[3],&I##ab=(tab)[4], \ &I##bp=(tab)[5],&I##pp=(tab)[6],&I##cp=(tab)[7],&I##np=(tab)[8],&I##ap=(tab)[9], \ &I##bc=(tab)[10],&I##pc=(tab)[11],&I##cc=(tab)[12],&I##nc=(tab)[13],&I##ac=(tab)[14], \ &I##bn=(tab)[15],&I##pn=(tab)[16],&I##cn=(tab)[17],&I##nn=(tab)[18],&I##an=(tab)[19], \ &I##ba=(tab)[20],&I##pa=(tab)[21],&I##ca=(tab)[22],&I##na=(tab)[23],&I##aa=(tab)[24] #define CImg_2x2x2_ref(I,T,tab) T &I##ccc=(tab)[0],&I##ncc=(tab)[1],&I##cnc=(tab)[2],&I##nnc=(tab)[3], \ &I##ccn=(tab)[4],&I##ncn=(tab)[5],&I##cnn=(tab)[6],&I##nnn=(tab)[7] #define CImg_3x3x3_ref(I,T,tab) T &I##ppp=(tab)[0],&I##cpp=(tab)[1],&I##npp=(tab)[2], \ &I##pcp=(tab)[3],&I##ccp=(tab)[4],&I##ncp=(tab)[5], \ &I##pnp=(tab)[6],&I##cnp=(tab)[7],&I##nnp=(tab)[8], \ &I##ppc=(tab)[9],&I##cpc=(tab)[10],&I##npc=(tab)[11], \ &I##pcc=(tab)[12],&I##ccc=(tab)[13],&I##ncc=(tab)[14], \ &I##pnc=(tab)[15],&I##cnc=(tab)[16],&I##nnc=(tab)[17], \ &I##ppn=(tab)[18],&I##cpn=(tab)[19],&I##npn=(tab)[20], \ &I##pcn=(tab)[21],&I##ccn=(tab)[22],&I##ncn=(tab)[23], \ &I##pnn=(tab)[24],&I##cnn=(tab)[25],&I##nnn=(tab)[26] #define cimg_copy2x2(J,I) I##cc=J##cc, I##nc=J##nc, I##cn=J##cn, I##nn=J##nn #define cimg_copy3x3(J,I) I##pp=J##pp, I##cp=J##cp, I##np=J##np, \ I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, \ I##pn=J##pn, I##cn=J##cn, I##nn=J##nn #define cimg_copy5x5(J,I) I##bb=J##bb, I##pb=J##pb, I##cb=J##cb, I##nb=J##nb, I##ab=J##ab, \ I##bp=J##bp, I##pp=J##pp, I##cp=J##cp, I##np=J##np, I##ap=J##ap, \ I##bc=J##bc, I##pc=J##pc, I##cc=J##cc, I##nc=J##nc, I##ac=J##ac, \ I##bn=J##bn, I##pn=J##pn, I##cn=J##cn, I##nn=J##nn, I##an=J##an, \ I##ba=J##ba, I##pa=J##pa, I##ca=J##ca, I##na=J##na, I##aa=J##aa #define cimg_squaresum2x2(I) ( I##cc*I##cc + I##nc*I##nc + I##cn*I##cn + I##nn*I##nn ) #define cimg_squaresum3x3(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + \ I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + \ I##pn*I##pn + I##cn*I##cn + I##nn*I##nn ) #define cimg_squaresum4x4(I) ( I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \ I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \ I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \ I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa ) #define cimg_squaresum5x5(I) ( I##bb*I##bb + I##pb*I##pb + I##cb*I##cb + I##nb*I##nb + I##ab*I##ab + \ I##bp*I##bp + I##pp*I##pp + I##cp*I##cp + I##np*I##np + I##ap*I##ap + \ I##bc*I##bc + I##pc*I##pc + I##cc*I##cc + I##nc*I##nc + I##ac*I##ac + \ I##bn*I##bn + I##pn*I##pn + I##cn*I##cn + I##nn*I##nn + I##an*I##an + \ I##ba*I##ba + I##pa*I##pa + I##ca*I##ca + I##na*I##na + I##aa*I##aa ) #define cimg_squaresum2x2x2(I) ( I##ccc*I##ccc + I##ncc*I##ncc + I##cnc*I##cnc + I##nnc*I##nnc + \ I##ccn*I##ccn + I##ncn*I##ncn + I##cnn*I##cnn + I##nnn*I##nnn ) #define cimg_squaresum3x3x3(I) ( I##ppp*I##ppp + I##cpp*I##cpp + I##npp*I##npp + \ I##pcp*I##pcp + I##ccp*I##ccp + I##ncp*I##ncp + \ I##pnp*I##pnp + I##cnp*I##cnp + I##nnp*I##nnp + \ I##ppc*I##ppc + I##cpc*I##cpc + I##npc*I##npc + \ I##pcc*I##pcc + I##ccc*I##ccc + I##ncc*I##ncc + \ I##pnc*I##pnc + I##cnc*I##cnc + I##nnc*I##nnc + \ I##ppn*I##ppn + I##cpn*I##cpn + I##npn*I##npn + \ I##pcn*I##pcn + I##ccn*I##ccn + I##ncn*I##ncn + \ I##pnn*I##pnn + I##cnn*I##cnn + I##nnn*I##nnn ) #define cimg_corr2x2(I,m) ( I##cc*(m)(0,0)+I##nc*(m)(1,0)+I##cn*(m)(0,1)+I##nn*(m)(1,1) ) #define cimg_corr3x3(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0) + \ I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1) + \ I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2) ) #define cimg_corr4x4(I,m) ( I##pp*(m)(0,0)+I##cp*(m)(1,0)+I##np*(m)(2,0)+I##ap*(m)(3,0) + \ I##pc*(m)(0,1)+I##cc*(m)(1,1)+I##nc*(m)(2,1)+I##ac*(m)(3,1) + \ I##pn*(m)(0,2)+I##cn*(m)(1,2)+I##nn*(m)(2,2)+I##an*(m)(3,2) + \ I##pa*(m)(0,3)+I##ca*(m)(1,3)+I##na*(m)(2,3)+I##aa*(m)(3,3) ) #define cimg_corr5x5(I,m) ( I##bb*(m)(0,0)+I##pb*(m)(1,0)+I##cb*(m)(2,0)+I##nb*(m)(3,0)+I##ab*(m)(4,0) + \ I##bp*(m)(0,1)+I##pp*(m)(1,1)+I##cp*(m)(2,1)+I##np*(m)(3,1)+I##ap*(m)(4,1) + \ I##bc*(m)(0,2)+I##pc*(m)(1,2)+I##cc*(m)(2,2)+I##nc*(m)(3,2)+I##ac*(m)(4,2) + \ I##bn*(m)(0,3)+I##pn*(m)(1,3)+I##cn*(m)(2,3)+I##nn*(m)(3,3)+I##an*(m)(4,3) + \ I##ba*(m)(0,4)+I##pa*(m)(1,4)+I##ca*(m)(2,4)+I##na*(m)(3,4)+I##aa*(m)(4,4) ) #define cimg_corr2x2x2(I,m) ( I##ccc*(m)(0,0,0)+I##ncc*(m)(1,0,0)+I##cnc*(m)(0,1,0)+I##nnc*(m)(1,1,0) + \ I##ccn*(m)(0,0,1)+I##ncn*(m)(1,0,1)+I##cnn*(m)(0,1,1)+I##nnn*(m)(1,1,1) ) #define cimg_corr3x3x3(I,m) ( I##ppp*(m)(0,0,0)+I##cpp*(m)(1,0,0)+I##npp*(m)(2,0,0) + \ I##pcp*(m)(0,1,0)+I##ccp*(m)(1,1,0)+I##ncp*(m)(2,1,0) + \ I##pnp*(m)(0,2,0)+I##cnp*(m)(1,2,0)+I##nnp*(m)(2,2,0) + \ I##ppc*(m)(0,0,1)+I##cpc*(m)(1,0,1)+I##npc*(m)(2,0,1) + \ I##pcc*(m)(0,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(2,1,1) + \ I##pnc*(m)(0,2,1)+I##cnc*(m)(1,2,1)+I##nnc*(m)(2,2,1) + \ I##ppn*(m)(0,0,2)+I##cpn*(m)(1,0,2)+I##npn*(m)(2,0,2) + \ I##pcn*(m)(0,1,2)+I##ccn*(m)(1,1,2)+I##ncn*(m)(2,1,2) + \ I##pnn*(m)(0,2,2)+I##cnn*(m)(1,2,2)+I##nnn*(m)(2,2,2) ) #define cimg_conv2x2(I,m) ( I##cc*(m)(1,1)+I##nc*(m)(0,1)+I##cn*(m)(1,0)+I##nn*(m)(0,0) ) #define cimg_conv3x3(I,m) ( I##pp*(m)(2,2)+I##cp*(m)(1,2)+I##np*(m)(0,2) + \ I##pc*(m)(2,1)+I##cc*(m)(1,1)+I##nc*(m)(0,1) + \ I##pn*(m)(2,0)+I##cn*(m)(1,0)+I##nn*(m)(0,0) ) #define cimg_conv4x4(I,m) ( I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \ I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \ I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \ I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) ) #define cimg_conv5x5(I,m) ( I##bb*(m)(4,4)+I##pb*(m)(3,4)+I##cb*(m)(2,4)+I##nb*(m)(1,4)+I##ab*(m)(0,4) + \ I##bp*(m)(4,3)+I##pp*(m)(3,3)+I##cp*(m)(2,3)+I##np*(m)(1,3)+I##ap*(m)(0,3) + \ I##bc*(m)(4,2)+I##pc*(m)(3,2)+I##cc*(m)(2,2)+I##nc*(m)(1,2)+I##ac*(m)(0,2) + \ I##bn*(m)(4,1)+I##pn*(m)(3,1)+I##cn*(m)(2,1)+I##nn*(m)(1,1)+I##an*(m)(0,1) + \ I##ba*(m)(4,0)+I##pa*(m)(3,0)+I##ca*(m)(2,0)+I##na*(m)(1,0)+I##aa*(m)(0,0) ) #define cimg_conv2x2x2(I,m) ( I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \ I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) ) #define cimg_conv3x3x3(I,m) ( I##ppp*(m)(2,2,2)+I##cpp*(m)(1,2,2)+I##npp*(m)(0,2,2) + \ I##pcp*(m)(2,1,2)+I##ccp*(m)(1,1,2)+I##ncp*(m)(0,1,2) + \ I##pnp*(m)(2,0,2)+I##cnp*(m)(1,0,2)+I##nnp*(m)(0,0,2) + \ I##ppc*(m)(2,2,1)+I##cpc*(m)(1,2,1)+I##npc*(m)(0,2,1) + \ I##pcc*(m)(2,1,1)+I##ccc*(m)(1,1,1)+I##ncc*(m)(0,1,1) + \ I##pnc*(m)(2,0,1)+I##cnc*(m)(1,0,1)+I##nnc*(m)(0,0,1) + \ I##ppn*(m)(2,2,0)+I##cpn*(m)(1,2,0)+I##npn*(m)(0,2,0) + \ I##pcn*(m)(2,1,0)+I##ccn*(m)(1,1,0)+I##ncn*(m)(0,1,0) + \ I##pnn*(m)(2,0,0)+I##cnn*(m)(1,0,0)+I##nnn*(m)(0,0,0) ) #define cimg_get2x2(img,x,y,z,v,I) \ I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), \ I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v) #define cimg_get3x3(img,x,y,z,v,I) \ I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), \ I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), \ I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v) #define cimg_get4x4(img,x,y,z,v,I) \ I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \ I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), I##ac=(img)(_a##x, y,z,v), \ I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \ I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v) #define cimg_get5x5(img,x,y,z,v,I) \ I##bb=(img)(_b##x,_b##y,z,v), I##pb=(img)(_p##x,_b##y,z,v), I##cb=(img)(x,_b##y,z,v), I##nb=(img)(_n##x,_b##y,z,v), I##ab=(img)(_a##x,_b##y,z,v), \ I##bp=(img)(_b##x,_p##y,z,v), I##pp=(img)(_p##x,_p##y,z,v), I##cp=(img)(x,_p##y,z,v), I##np=(img)(_n##x,_p##y,z,v), I##ap=(img)(_a##x,_p##y,z,v), \ I##bc=(img)(_b##x, y,z,v), I##pc=(img)(_p##x, y,z,v), I##cc=(img)(x, y,z,v), I##nc=(img)(_n##x, y,z,v), I##ac=(img)(_a##x, y,z,v), \ I##bn=(img)(_b##x,_n##y,z,v), I##pn=(img)(_p##x,_n##y,z,v), I##cn=(img)(x,_n##y,z,v), I##nn=(img)(_n##x,_n##y,z,v), I##an=(img)(_a##x,_n##y,z,v), \ I##ba=(img)(_b##x,_a##y,z,v), I##pa=(img)(_p##x,_a##y,z,v), I##ca=(img)(x,_a##y,z,v), I##na=(img)(_n##x,_a##y,z,v), I##aa=(img)(_a##x,_a##y,z,v) #define cimg_get2x2x2(img,x,y,z,v,I) \ I##ccc=(img)(x,y, z,v), I##ncc=(img)(_n##x,y, z,v), I##cnc=(img)(x,_n##y, z,v), I##nnc=(img)(_n##x,_n##y, z,v), \ I##ccc=(img)(x,y,_n##z,v), I##ncc=(img)(_n##x,y,_n##z,v), I##cnc=(img)(x,_n##y,_n##z,v), I##nnc=(img)(_n##x,_n##y,_n##z,v) #define cimg_get3x3x3(img,x,y,z,v,I) \ I##ppp=(img)(_p##x,_p##y,_p##z,v), I##cpp=(img)(x,_p##y,_p##z,v), I##npp=(img)(_n##x,_p##y,_p##z,v), \ I##pcp=(img)(_p##x, y,_p##z,v), I##ccp=(img)(x, y,_p##z,v), I##ncp=(img)(_n##x, y,_p##z,v), \ I##pnp=(img)(_p##x,_n##y,_p##z,v), I##cnp=(img)(x,_n##y,_p##z,v), I##nnp=(img)(_n##x,_n##y,_p##z,v), \ I##ppc=(img)(_p##x,_p##y, z,v), I##cpc=(img)(x,_p##y, z,v), I##npc=(img)(_n##x,_p##y, z,v), \ I##pcc=(img)(_p##x, y, z,v), I##ccc=(img)(x, y, z,v), I##ncc=(img)(_n##x, y, z,v), \ I##pnc=(img)(_p##x,_n##y, z,v), I##cnc=(img)(x,_n##y, z,v), I##nnc=(img)(_n##x,_n##y, z,v), \ I##ppn=(img)(_p##x,_p##y,_n##z,v), I##cpn=(img)(x,_p##y,_n##z,v), I##npn=(img)(_n##x,_p##y,_n##z,v), \ I##pcn=(img)(_p##x, y,_n##z,v), I##ccn=(img)(x, y,_n##z,v), I##ncn=(img)(_n##x, y,_n##z,v), \ I##pnn=(img)(_p##x,_n##y,_n##z,v), I##cnn=(img)(x,_n##y,_n##z,v), I##nnn=(img)(_n##x,_n##y,_n##z,v) // Macros used to define special image loops. // (see module 'Using Image Loops' in the generated documentation). #define cimg_for(img,ptr,T_ptr) for (T_ptr *ptr=(img).data+(img).size(); (ptr--)>(img).data; ) #define cimglist_for(list,l) for (unsigned int l=0; l<(list).size; l++) #define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn #define cimg_foroff(img,off) for (unsigned int off=0; off<(img).size(); off++) #define cimg_forX(img,x) for (int x=0; x<(int)((img).width); x++) #define cimg_forY(img,y) for (int y=0; y<(int)((img).height);y++) #define cimg_forZ(img,z) for (int z=0; z<(int)((img).depth); z++) #define cimg_forV(img,v) for (int v=0; v<(int)((img).dim); v++) #define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x) #define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x) #define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y) #define cimg_forXV(img,x,v) cimg_forV(img,v) cimg_forX(img,x) #define cimg_forYV(img,y,v) cimg_forV(img,v) cimg_forY(img,y) #define cimg_forZV(img,z,v) cimg_forV(img,v) cimg_forZ(img,z) #define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y) #define cimg_forXYV(img,x,y,v) cimg_forV(img,v) cimg_forXY(img,x,y) #define cimg_forXZV(img,x,z,v) cimg_forV(img,v) cimg_forXZ(img,x,z) #define cimg_forYZV(img,y,z,v) cimg_forV(img,v) cimg_forYZ(img,y,z) #define cimg_forXYZV(img,x,y,z,v) cimg_forV(img,v) cimg_forXYZ(img,x,y,z) #define cimg_for_insideX(img,x,n) for (int x=(n); x<(int)((img).width-(n)); x++) #define cimg_for_insideY(img,y,n) for (int y=(n); y<(int)((img).height-(n)); y++) #define cimg_for_insideZ(img,z,n) for (int z=(n); z<(int)((img).depth-(n)); z++) #define cimg_for_insideV(img,v,n) for (int v=(n); v<(int)((img).dim-(n)); v++) #define cimg_for_insideXY(img,x,y,n) cimg_for_insideY(img,y,n) cimg_for_insideX(img,x,n) #define cimg_for_insideXYZ(img,x,y,z,n) cimg_for_insideZ(img,z,n) cimg_for_insideXY(img,x,y,n) #define cimg_for_borderX(img,x,n) for (int x=0; x<(int)((img).width); x==(n)-1?(x=(img).width-(n)): x++) #define cimg_for_borderY(img,y,n) for (int y=0; y<(int)((img).height); y==(n)-1?(x=(img).height-(n)):y++) #define cimg_for_borderZ(img,z,n) for (int z=0; z<(int)((img).depth); z==(n)-1?(x=(img).depth-(n)): z++) #define cimg_for_borderV(img,v,n) for (int v=0; v<(int)((img).dim); v==(n)-1?(x=(img).dim-(n)): v++) #define cimg_for_borderXY(img,x,y,n) cimg_forY(img,y) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n))?x++: \ ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n)))) #define cimg_for_borderXYZ(img,x,y,z,n) cimg_forYZ(img,y,z) for (int x=0; x<(int)((img).width); (y<(n) || y>=(int)((img).height)-(n) || z<(n) || z>=(int)((img).depth)-(n))?x++: \ ((x<(n)-1 || x>=(int)((img).width)-(n))?x++:(x=(img).width-(n)))) #define cimg_for_spiralXY(img,x,y) for (int x=0,y=0,_n##x=1,_n##y=(int)((img).width*(img).height); _n##y; \ --_n##y, _n##x += (_n##x>>2)-((!(_n##x&3)?--y:((_n##x&3)==1?(img).width-1-++x:((_n##x&3)==2?(img).height-1-++y:--x))))?0:1) #define cimg_for2X(img,x) for (int x=0,_n##x=1; _n##x<(int)((img).width) || x==--_n##x; x++, _n##x++) #define cimg_for2Y(img,y) for (int y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y; y++, _n##y++) #define cimg_for2Z(img,z) for (int z=0,_n##z=1; _n##z<(int)((img).depth) || z==--_n##z; z++, _n##z++) #define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x) #define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x) #define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y) #define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y) #define cimg_for3X(img,x) for (int x=0,_p##x=0,_n##x=1; _n##x<(int)((img).width) || x==--_n##x; _p##x=x++,_n##x++) #define cimg_for3Y(img,y) for (int y=0,_p##y=0,_n##y=1; _n##y<(int)((img).height) || y==--_n##y; _p##y=y++,_n##y++) #define cimg_for3Z(img,z) for (int z=0,_p##z=0,_n##z=1; _n##z<(int)((img).depth) || z==--_n##z; _p##z=z++,_n##z++) #define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x) #define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x) #define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y) #define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y) #define cimg_for4X(img,x) for (int _p##x=0,x=0,_n##x=1,_a##x=2; \ _a##x<(int)((img).width) || _n##x==--_a##x || x==(_a##x=--_n##x); \ _p##x=x++,_n##x++,_a##x++) #define cimg_for4Y(img,y) for (int _p##y=0,y=0,_n##y=1,_a##y=2; \ _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \ _p##y=y++,_n##y++,_a##y++) #define cimg_for4Z(img,z) for (int _p##z=0,z=0,_n##z=1,_a##z=2; \ _a##z<(int)((img).depth) || _n##z==--_a##z || z==(_a##z=--_n##z); \ _p##z=z++,_n##z++,_a##z++) #define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x) #define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x) #define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y) #define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y) #define cimg_for5X(img,x) for (int _b##x=0,_p##x=0,x=0,_n##x=1,_a##x=2; \ _a##x<(int)((img).width) || _n##x==--_a##x || x==(_a##x=--_n##x); \ _b##x=_p##x,_p##x=x++,_n##x++,_a##x++) #define cimg_for5Y(img,y) for (int _b##y=0,_p##y=0,y=0,_n##y=1,_a##y=2; \ _a##y<(int)((img).height) || _n##y==--_a##y || y==(_a##y=--_n##y); \ _b##y=_p##y,_p##y=y++,_n##y++,_a##y++) #define cimg_for5Z(img,z) for (int _b##z=0,_p##z=0,z=0,_n##z=1,_a##z=2; \ _a##z<(int)((img).depth) || _n##z==--_a##z || z==(_a##z=--_n##z); \ _b##z=_p##z,_p##z=z++,_n##z++,_a##z++) #define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x) #define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x) #define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y) #define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y) #define cimg_for2x2(img,x,y,z,v,I) cimg_for2Y(img,y) \ for (int _n##x=1, x=(int)((I##cc=(img)(0, y,z,v)), \ (I##cn=(img)(0,_n##y,z,v)), \ 0); \ (_n##x<(int)((img).width) && ((I##nc=(img)(_n##x, y,z,v)), \ (I##nn=(img)(_n##x,_n##y,z,v)), \ 1)) || x==--_n##x; \ I##cc=I##nc, I##cn=I##nn, \ x++,_n##x++ ) #define cimg_for3x3(img,x,y,z,v,I) cimg_for3Y(img,y) \ for (int _n##x=1, _p##x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \ (I##cc=I##pc=(img)(0, y,z,v)), \ (I##cn=I##pn=(img)(0,_n##y,z,v))), \ x=_p##x=0; \ (_n##x<(int)((img).width) && ((I##np=(img)(_n##x,_p##y,z,v)), \ (I##nc=(img)(_n##x, y,z,v)), \ (I##nn=(img)(_n##x,_n##y,z,v)), \ 1)) || x==--_n##x; \ I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, \ I##cp=I##np, I##cc=I##nc, I##cn=I##nn, \ _p##x=x++,_n##x++ ) #define cimg_for4x4(img,x,y,z,v,I) cimg_for4Y(img,y) \ for (int _a##x=2, _n##x=1, x=(int)((I##cp=I##pp=(img)(0,_p##y,z,v)), \ (I##cc=I##pc=(img)(0, y,z,v)), \ (I##cn=I##pn=(img)(0,_n##y,z,v)), \ (I##ca=I##pa=(img)(0,_a##y,z,v)), \ (I##np=(img)(_n##x,_p##y,z,v)), \ (I##nc=(img)(_n##x, y,z,v)), \ (I##nn=(img)(_n##x,_n##y,z,v)), \ (I##na=(img)(_n##x,_a##y,z,v)), \ 0), _p##x=0; \ (_a##x<(int)((img).width) && ((I##ap=(img)(_a##x,_p##y,z,v)), \ (I##ac=(img)(_a##x, y,z,v)), \ (I##an=(img)(_a##x,_n##y,z,v)), \ (I##aa=(img)(_a##x,_a##y,z,v)), \ 1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \ I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \ I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \ I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \ _p##x=x++, _n##x++, _a##x++ ) #define cimg_for5x5(img,x,y,z,v,I) cimg_for5Y(img,y) \ for (int _a##x=2, _n##x=1, _b##x=(int)((I##cb=I##pb=I##bb=(img)(0,_b##y,z,v)), \ (I##cp=I##pp=I##bp=(img)(0,_p##y,z,v)), \ (I##cc=I##pc=I##bc=(img)(0, y,z,v)), \ (I##cn=I##pn=I##bn=(img)(0,_n##y,z,v)), \ (I##ca=I##pa=I##ba=(img)(0,_a##y,z,v)), \ (I##nb=(img)(_n##x,_b##y,z,v)), \ (I##np=(img)(_n##x,_p##y,z,v)), \ (I##nc=(img)(_n##x, y,z,v)), \ (I##nn=(img)(_n##x,_n##y,z,v)), \ (I##na=(img)(_n##x,_a##y,z,v))), \ x=0, _p##x=_b##x=0; \ (_a##x<(int)((img).width) && ((I##ab=(img)(_a##x,_b##y,z,v)), \ (I##ap=(img)(_a##x,_p##y,z,v)), \ (I##ac=(img)(_a##x, y,z,v)), \ (I##an=(img)(_a##x,_n##y,z,v)), \ (I##aa=(img)(_a##x,_a##y,z,v)), \ 1)) || _n##x==--_a##x || x==(_a##x=--_n##x); \ I##bb=I##pb, I##bp=I##pp, I##bc=I##pc, I##bn=I##pn, I##ba=I##pa, \ I##pb=I##cb, I##pp=I##cp, I##pc=I##cc, I##pn=I##cn, I##pa=I##ca, \ I##cb=I##nb, I##cp=I##np, I##cc=I##nc, I##cn=I##nn, I##ca=I##na, \ I##nb=I##ab, I##np=I##ap, I##nc=I##ac, I##nn=I##an, I##na=I##aa, \ _b##x=_p##x, _p##x=x++, _n##x++, _a##x++ ) #define cimg_for2x2x2(img,x,y,z,v,I) cimg_for2YZ(img,y,z) \ for (int _n##x=1, x=(int)((I##ccc=(img)(0, y, z,v)), \ (I##cnc=(img)(0,_n##y, z,v)), \ (I##ccn=(img)(0, y,_n##z,v)), \ (I##cnn=(img)(0,_n##y,_n##z,v)), \ 0); \ (_n##x<(int)((img).width) && ((I##ncc=(img)(_n##x, y, z,v)), \ (I##nnc=(img)(_n##x,_n##y, z,v)), \ (I##ncn=(img)(_n##x, y,_n##z,v)), \ (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \ 1)) || x==--_n##x; \ I##ccc=I##ncc, I##cnc=I##nnc, \ I##ccn=I##ncn, I##cnn=I##nnn, \ x++, _n##x++ ) #define cimg_for3x3x3(img,x,y,z,v,I) cimg_for3YZ(img,y,z) \ for (int _n##x=1, _p##x=(int)((I##cpp=I##ppp=(img)(0,_p##y,_p##z,v)), \ (I##ccp=I##pcp=(img)(0, y,_p##z,v)), \ (I##cnp=I##pnp=(img)(0,_n##y,_p##z,v)), \ (I##cpc=I##ppc=(img)(0,_p##y, z,v)), \ (I##ccc=I##pcc=(img)(0, y, z,v)), \ (I##cnc=I##pnc=(img)(0,_n##y, z,v)), \ (I##cpn=I##ppn=(img)(0,_p##y,_n##z,v)), \ (I##ccn=I##pcn=(img)(0, y,_n##z,v)), \ (I##cnn=I##pnn=(img)(0,_n##y,_n##z,v))),\ x=_p##x=0; \ (_n##x<(int)((img).width) && ((I##npp=(img)(_n##x,_p##y,_p##z,v)), \ (I##ncp=(img)(_n##x, y,_p##z,v)), \ (I##nnp=(img)(_n##x,_n##y,_p##z,v)), \ (I##npc=(img)(_n##x,_p##y, z,v)), \ (I##ncc=(img)(_n##x, y, z,v)), \ (I##nnc=(img)(_n##x,_n##y, z,v)), \ (I##npn=(img)(_n##x,_p##y,_n##z,v)), \ (I##ncn=(img)(_n##x, y,_n##z,v)), \ (I##nnn=(img)(_n##x,_n##y,_n##z,v)), \ 1)) || x==--_n##x; \ I##ppp=I##cpp, I##pcp=I##ccp, I##pnp=I##cnp, \ I##cpp=I##npp, I##ccp=I##ncp, I##cnp=I##nnp, \ I##ppc=I##cpc, I##pcc=I##ccc, I##pnc=I##cnc, \ I##cpc=I##npc, I##ccc=I##ncc, I##cnc=I##nnc, \ I##ppn=I##cpn, I##pcn=I##ccn, I##pnn=I##cnn, \ I##cpn=I##npn, I##ccn=I##ncn, I##cnn=I##nnn, \ _p##x=x++, _n##x++ ) /* #------------------------------------------------ # # # Definition of the cimg_library:: namespace # # #------------------------------------------------ */ //! Namespace that encompasses all classes and functions of the %CImg library. /** This namespace is defined to avoid class names collisions that could happen with the include of other C++ header files. Anyway, it should not happen very often and you may start most of your programs with \code #include "CImg.h" using namespace cimg_library; \endcode to simplify the declaration of %CImg Library objects variables afterwards. **/ namespace cimg_library { // Define the CImg classes. template struct CImg; template struct CImgList; struct CImgStats; struct CImgDisplay; struct CImgException; namespace cimg { // The bodies of the functions below are defined afterwards inline void info(); inline unsigned int& exception_mode(); inline int dialog(const char *title,const char *msg,const char *button1_txt="OK", const char *button2_txt=0,const char *button3_txt=0, const char *button4_txt=0,const char *button5_txt=0, const char *button6_txt=0,const bool centering = false); template inline void marching_cubes(const tfunc& func, const float isovalue, const float x0,const float y0,const float z0, const float x1,const float y1,const float z1, const float resx,const float resy,const float resz, CImgList& points, CImgList& primitives, const bool invert_faces = false); template inline void marching_squares(const tfunc& func, const float isovalue, const float x0,const float y0, const float x1,const float y1, const float resx,const float resy, CImgList& points, CImgList& primitives); } /* #---------------------------------------------- # # # Definition of the CImgException structures # # #---------------------------------------------- */ // Never use the following macro in your own code ! #define cimg_exception_err(etype,disp_flag) \ std::va_list ap; \ va_start(ap,format); \ std::vsprintf(message,format,ap); \ va_end(ap); \ if (cimg::exception_mode()>=1) { \ if (cimg::exception_mode()>=2 && disp_flag) { \ try { cimg::dialog(etype,message,"Abort"); } \ catch (CImgException&) { std::fprintf(stderr,"\n# %s :\n%s\n\n",etype,message); } \ } else std::fprintf(stderr,"\n# %s :\n%s\n\n",etype,message); \ } \ if (cimg::exception_mode()>=3) cimg_library::cimg::info(); \ //! Class which is thrown when an error occured during a %CImg library function call. /** \section ex1 Overview CImgException is the base class of %CImg exceptions. Exceptions are thrown by the %CImg Library when an error occured in a %CImg library function call. CImgException is seldom thrown itself. Children classes that specify the kind of error encountered are generally used instead. These sub-classes are : - \b CImgInstanceException : Thrown when the instance associated to the called %CImg function is not correctly defined. Generally, this exception is thrown when one tries to process \a empty images. The example below will throw a \a CImgInstanceException. \code CImg img; // Construct an empty image. img.blur(10); // Try to blur the image. \endcode - \b CImgArgumentException : Thrown when one of the arguments given to the called %CImg function is not correct. Generally, this exception is thrown when arguments passed to the function are outside an admissible range of values. The example below will throw a \a CImgArgumentException. \code CImg img(100,100,1,3); // Define a 100x100 color image with float pixels. img = 0; // Try to fill pixels from the 0 pointer (invalid argument to operator=() ). \endcode - \b CImgIOException : Thrown when an error occured when trying to load or save image files. The example below will throw a \a CImgIOException. \code CImg img("file_doesnt_exist.jpg"); // Try to load a file that doesn't exist. \endcode - \b CImgDisplayException : Thrown when an error occured when trying to display an image in a window. This exception is thrown when image display request cannot be satisfied. The parent class CImgException may be thrown itself when errors that cannot be classified in one of the above type occur. It is recommended not to throw CImgExceptions yourself, since there are normally reserved to %CImg Library functions. \b CImgInstanceException, \b CImgArgumentException, \b CImgIOException and \b CImgDisplayException are simple subclasses of CImgException and are thus not detailled more in this reference documentation. \section ex2 Exception handling When an error occurs, the %CImg Library first displays the error in a modal window. Then, it throws an instance of the corresponding exception class, generally leading the program to stop (this is the default behavior). You can bypass this default behavior by handling the exceptions yourself, using a code block try { ... } catch() { ... }. In this case, you can avoid the apparition of the modal window, by defining the environment variable cimg_debug to 0 before including the %CImg header file. The example below shows how to cleanly handle %CImg Library exceptions : \code #define cimg_debug 0 // Disable modal window in CImg exceptions. #define "CImg.h" int main() { try { ...; // Here, do what you want. } catch (CImgInstanceException &e) { std::fprintf(stderr,"CImg Library Error : %s",e.message); // Display your own error message ... // Do what you want now. } } \endcode **/ struct CImgException { char message[1024]; //!< Message associated with the error that thrown the exception. CImgException() { message[0]='\0'; } CImgException(const char *format,...) { cimg_exception_err("CImgException",true); } }; // The \ref CImgInstanceException class is used to throw an exception related // to a non suitable instance encountered in a library function call. struct CImgInstanceException : CImgException { CImgInstanceException(const char *format,...) { cimg_exception_err("CImgInstanceException",true); } }; // The \ref CImgArgumentException class is used to throw an exception related // to invalid arguments encountered in a library function call. struct CImgArgumentException : CImgException { CImgArgumentException(const char *format,...) { cimg_exception_err("CImgArgumentException",true); } }; // The \ref CImgIOException class is used to throw an exception related // to Input/Output file problems encountered in a library function call. struct CImgIOException : CImgException { CImgIOException(const char *format,...) { cimg_exception_err("CImgIOException",true); } }; // The CImgDisplayException class is used to throw an exception related to display problems // encountered in a library function call. struct CImgDisplayException : CImgException { CImgDisplayException(const char *format,...) { cimg_exception_err("CImgDisplayException",false); } }; /* #------------------------------------- # # # Definition of the namespace 'cimg' # # #------------------------------------- */ //! Namespace that encompasses \a low-level functions and variables of the %CImg Library. /** Most of the functions and variables within this namespace are used by the library for low-level processing. Nevertheless, documented variables and functions of this namespace may be used safely in your own source code. \warning Never write using namespace cimg_library::cimg; in your source code, since a lot of functions of the cimg:: namespace have prototypes similar to standard C functions defined in the global namespace ::. **/ namespace cimg { // Define the trait that will be used to determine the best data type to work with. // Considered types are : bool, uchar, char, short, ushort, int, uint, long, ulong, float and double. // Two rules applies there : // - largest of two integer types is an integer type. // - largest of integer/float type is a float type. template struct largest { typedef T type; }; template<> struct largest { typedef short type; }; template<> struct largest { typedef unsigned short type; }; template<> struct largest { typedef short type; }; template<> struct largest { typedef unsigned int type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef unsigned long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef short type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef short type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef unsigned int type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef unsigned long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef int type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef unsigned long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef long type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef float type; }; template<> struct largest { typedef double type; }; template<> struct largest { typedef double type; }; template struct type { static T min() { return (T)-1>0?(T)0:(T)-1<<(8*sizeof(T)-1); } static T max() { return (T)-1>0?(T)-1:~((T)-1<<(8*sizeof(T)-1)); } static bool is_float() { return false; } static const char* id() { static const char *const s = "unknown"; return s; } }; template<> struct type { static bool min() { return false; } static bool max() { return true; } static bool is_float() { return false; } static const char* id() { static const char *const s = "bool"; return s; } }; template<> struct type { static unsigned char min() { return 0; } static unsigned char max() { return (unsigned char)~0U; } static bool is_float() { return false; } static const char* id() { static const char *const s = "unsigned char"; return s; } }; template<> struct type { static char min() { return (char)(-1L<<(8*sizeof(char)-1)); } static char max() { return ~((char)(-1L<<(8*sizeof(char)-1))); } static bool is_float() { return false; } static const char* id() { static const char *const s = "char"; return s; } }; template<> struct type { static unsigned short min() { return 0; } static unsigned short max() { return (unsigned short)~0U; } static bool is_float() { return false; } static const char* id() { static const char *const s = "unsigned short"; return s; } }; template<> struct type { static short min() { return (short)(-1L<<(8*sizeof(short)-1)); } static short max() { return ~((short)(-1L<<(8*sizeof(short)-1))); } static bool is_float() { return false; } static const char* id() { static const char *const s = "short"; return s; } }; template<> struct type { static unsigned int min() { return 0; } static unsigned int max() { return (unsigned int)~0U; } static bool is_float() { return false; } static const char* id() { static const char *const s = "unsigned int"; return s; } }; template<> struct type { static int min() { return (int)(-1L<<(8*sizeof(int)-1)); } static int max() { return ~((int)(-1L<<(8*sizeof(int)-1))); } static bool is_float() { return false; } static const char* id() { static const char *const s = "int"; return s; } }; template<> struct type { static unsigned long min() { return 0; } static unsigned long max() { return (unsigned long)~0UL; } static bool is_float() { return false; } static const char* id() { static const char *const s = "unsigned long"; return s; } }; template<> struct type { static long min() { return (long)(-1L<<(8*sizeof(long)-1)); } static long max() { return ~((long)(-1L<<(8*sizeof(long)-1))); } static bool is_float() { return false; } static const char* id() { static const char *const s = "long"; return s; } }; template<> struct type { static float min() { return -3.4E38f; } static float max() { return 3.4E38f; } static bool is_float() { return true; } static const char* id() { static const char *const s = "float"; return s; } }; template<> struct type { static double min() { return -1.7E308; } static double max() { return 1.7E308; } static bool is_float() { return true; } static const char* id() { static const char *const s = "double"; return s; } }; // Define internal library variables. #if cimg_display_type==1 struct X11info { volatile unsigned int nb_wins; pthread_mutex_t* mutex; pthread_t* event_thread; CImgDisplay* wins[1024]; Display* display; unsigned int nb_bits; GC* gc; bool blue_first; bool byte_order; bool shm_enabled; #ifdef cimg_use_xrandr XRRScreenSize *resolutions; Rotation curr_rotation; unsigned int curr_resolution; unsigned int nb_resolutions; #endif X11info():nb_wins(0),mutex(0),event_thread(0),display(0), nb_bits(0),gc(0),blue_first(false),byte_order(false),shm_enabled(false) { #ifdef cimg_use_xrandr resolutions = 0; curr_rotation = 0; curr_resolution = nb_resolutions = 0; #endif } }; #if defined(cimg_module) X11info& X11attr(); #elif defined(cimg_main) X11info& X11attr() { static X11info val; return val; } #else inline X11info& X11attr() { static X11info val; return val; } #endif #elif cimg_display_type==2 struct Win32info { HANDLE wait_event; Win32info() { wait_event = CreateEvent(0,FALSE,FALSE,0); } }; #if defined(cimg_module) Win32info& Win32attr(); #elif defined(cimg_main) Win32info& Win32attr() { static Win32info val; return val; } #else inline Win32info& Win32attr() { static Win32info val; return val; } #endif #endif inline unsigned int& exception_mode() { static unsigned int mode = cimg_debug; return mode; } #ifdef cimg_color_terminal const char t_normal[9] = {0x1b,'[','0',';','0',';','0','m','\0'}; const char t_red[11] = {0x1b,'[','4',';','3','1',';','5','9','m','\0'}; const char t_bold[5] = {0x1b,'[','1','m','\0'}; const char t_purple[11] = {0x1b,'[','0',';','3','5',';','5','9','m','\0'}; #else const char t_normal[1] = {'\0'}; const char *const t_red = cimg::t_normal, *const t_bold = cimg::t_normal, *const t_purple = cimg::t_normal; #endif #if cimg_display_type==1 // Keycodes for X11-based graphical systems const unsigned int keyESC = XK_Escape; const unsigned int keyF1 = XK_F1; const unsigned int keyF2 = XK_F2; const unsigned int keyF3 = XK_F3; const unsigned int keyF4 = XK_F4; const unsigned int keyF5 = XK_F5; const unsigned int keyF6 = XK_F6; const unsigned int keyF7 = XK_F7; const unsigned int keyF8 = XK_F8; const unsigned int keyF9 = XK_F9; const unsigned int keyF10 = XK_F10; const unsigned int keyF11 = XK_F11; const unsigned int keyF12 = XK_F12; const unsigned int keyPAUSE = XK_Pause; const unsigned int key1 = XK_1; const unsigned int key2 = XK_2; const unsigned int key3 = XK_3; const unsigned int key4 = XK_4; const unsigned int key5 = XK_5; const unsigned int key6 = XK_6; const unsigned int key7 = XK_7; const unsigned int key8 = XK_8; const unsigned int key9 = XK_9; const unsigned int key0 = XK_0; const unsigned int keyBACKSPACE = XK_BackSpace; const unsigned int keyINSERT = XK_Insert; const unsigned int keyHOME = XK_Home; const unsigned int keyPAGEUP = XK_Page_Up; const unsigned int keyTAB = XK_Tab; const unsigned int keyQ = XK_q; const unsigned int keyW = XK_w; const unsigned int keyE = XK_e; const unsigned int keyR = XK_r; const unsigned int keyT = XK_t; const unsigned int keyY = XK_y; const unsigned int keyU = XK_u; const unsigned int keyI = XK_i; const unsigned int keyO = XK_o; const unsigned int keyP = XK_p; const unsigned int keyDELETE = XK_Delete; const unsigned int keyEND = XK_End; const unsigned int keyPAGEDOWN = XK_Page_Down; const unsigned int keyCAPSLOCK = XK_Caps_Lock; const unsigned int keyA = XK_a; const unsigned int keyS = XK_s; const unsigned int keyD = XK_d; const unsigned int keyF = XK_f; const unsigned int keyG = XK_g; const unsigned int keyH = XK_h; const unsigned int keyJ = XK_j; const unsigned int keyK = XK_k; const unsigned int keyL = XK_l; const unsigned int keyENTER = XK_Return; const unsigned int keySHIFTLEFT = XK_Shift_L; const unsigned int keyZ = XK_z; const unsigned int keyX = XK_x; const unsigned int keyC = XK_c; const unsigned int keyV = XK_v; const unsigned int keyB = XK_b; const unsigned int keyN = XK_n; const unsigned int keyM = XK_m; const unsigned int keySHIFTRIGHT = XK_Shift_R; const unsigned int keyARROWUP = XK_Up; const unsigned int keyCTRLLEFT = XK_Control_L; const unsigned int keyAPPLEFT = XK_Super_L; const unsigned int keySPACE = XK_space; const unsigned int keyALTGR = XK_Alt_R; const unsigned int keyAPPRIGHT = XK_Super_R; const unsigned int keyMENU = XK_Menu; const unsigned int keyCTRLRIGHT = XK_Control_R; const unsigned int keyARROWLEFT = XK_Left; const unsigned int keyARROWDOWN = XK_Down; const unsigned int keyARROWRIGHT = XK_Right; const unsigned int keyPAD0 = XK_KP_0; const unsigned int keyPAD1 = XK_KP_1; const unsigned int keyPAD2 = XK_KP_2; const unsigned int keyPAD3 = XK_KP_3; const unsigned int keyPAD4 = XK_KP_4; const unsigned int keyPAD5 = XK_KP_5; const unsigned int keyPAD6 = XK_KP_6; const unsigned int keyPAD7 = XK_KP_7; const unsigned int keyPAD8 = XK_KP_8; const unsigned int keyPAD9 = XK_KP_9; const unsigned int keyPADADD = XK_KP_Add; const unsigned int keyPADSUB = XK_KP_Subtract; const unsigned int keyPADMUL = XK_KP_Multiply; const unsigned int keyPADDIV = XK_KP_Divide; #elif (cimg_display_type==2 && cimg_OS==2) // Keycodes for Windows-OS const unsigned int keyESC = VK_ESCAPE; const unsigned int keyF1 = VK_F1; const unsigned int keyF2 = VK_F2; const unsigned int keyF3 = VK_F3; const unsigned int keyF4 = VK_F4; const unsigned int keyF5 = VK_F5; const unsigned int keyF6 = VK_F6; const unsigned int keyF7 = VK_F7; const unsigned int keyF8 = VK_F8; const unsigned int keyF9 = VK_F9; const unsigned int keyF10 = VK_F10; const unsigned int keyF11 = VK_F11; const unsigned int keyF12 = VK_F12; const unsigned int keyPAUSE = VK_PAUSE; const unsigned int key1 = '1'; const unsigned int key2 = '2'; const unsigned int key3 = '3'; const unsigned int key4 = '4'; const unsigned int key5 = '5'; const unsigned int key6 = '6'; const unsigned int key7 = '7'; const unsigned int key8 = '8'; const unsigned int key9 = '9'; const unsigned int key0 = '0'; const unsigned int keyBACKSPACE = VK_BACK; const unsigned int keyINSERT = VK_INSERT; const unsigned int keyHOME = VK_HOME; const unsigned int keyPAGEUP = VK_PRIOR; const unsigned int keyTAB = VK_TAB; const unsigned int keyQ = 'Q'; const unsigned int keyW = 'W'; const unsigned int keyE = 'E'; const unsigned int keyR = 'R'; const unsigned int keyT = 'T'; const unsigned int keyY = 'Y'; const unsigned int keyU = 'U'; const unsigned int keyI = 'I'; const unsigned int keyO = 'O'; const unsigned int keyP = 'P'; const unsigned int keyDELETE = VK_DELETE; const unsigned int keyEND = VK_END; const unsigned int keyPAGEDOWN = VK_NEXT; const unsigned int keyCAPSLOCK = VK_CAPITAL; const unsigned int keyA = 'A'; const unsigned int keyS = 'S'; const unsigned int keyD = 'D'; const unsigned int keyF = 'F'; const unsigned int keyG = 'G'; const unsigned int keyH = 'H'; const unsigned int keyJ = 'J'; const unsigned int keyK = 'K'; const unsigned int keyL = 'L'; const unsigned int keyENTER = VK_RETURN; const unsigned int keySHIFTLEFT = VK_SHIFT; const unsigned int keyZ = 'Z'; const unsigned int keyX = 'X'; const unsigned int keyC = 'C'; const unsigned int keyV = 'V'; const unsigned int keyB = 'B'; const unsigned int keyN = 'N'; const unsigned int keyM = 'M'; const unsigned int keySHIFTRIGHT = VK_SHIFT; const unsigned int keyARROWUP = VK_UP; const unsigned int keyCTRLLEFT = VK_CONTROL; const unsigned int keyAPPLEFT = VK_LWIN; const unsigned int keySPACE = VK_SPACE; const unsigned int keyALTGR = VK_CONTROL; const unsigned int keyAPPRIGHT = VK_RWIN; const unsigned int keyMENU = VK_APPS; const unsigned int keyCTRLRIGHT = VK_CONTROL; const unsigned int keyARROWLEFT = VK_LEFT; const unsigned int keyARROWDOWN = VK_DOWN; const unsigned int keyARROWRIGHT = VK_RIGHT; const unsigned int keyPAD0 = 0x60; const unsigned int keyPAD1 = 0x61; const unsigned int keyPAD2 = 0x62; const unsigned int keyPAD3 = 0x63; const unsigned int keyPAD4 = 0x64; const unsigned int keyPAD5 = 0x65; const unsigned int keyPAD6 = 0x66; const unsigned int keyPAD7 = 0x67; const unsigned int keyPAD8 = 0x68; const unsigned int keyPAD9 = 0x69; const unsigned int keyPADADD = VK_ADD; const unsigned int keyPADSUB = VK_SUBTRACT; const unsigned int keyPADMUL = VK_MULTIPLY; const unsigned int keyPADDIV = VK_DIVIDE; #else // Define unknow keycodes when no display const unsigned int keyESC = 1U; const unsigned int keyF1 = 2U; const unsigned int keyF2 = 3U; const unsigned int keyF3 = 4U; const unsigned int keyF4 = 5U; const unsigned int keyF5 = 6U; const unsigned int keyF6 = 7U; const unsigned int keyF7 = 8U; const unsigned int keyF8 = 9U; const unsigned int keyF9 = 10U; const unsigned int keyF10 = 11U; const unsigned int keyF11 = 12U; const unsigned int keyF12 = 13U; const unsigned int keyPAUSE = 14U; const unsigned int key1 = 15U; const unsigned int key2 = 16U; const unsigned int key3 = 17U; const unsigned int key4 = 18U; const unsigned int key5 = 19U; const unsigned int key6 = 20U; const unsigned int key7 = 21U; const unsigned int key8 = 22U; const unsigned int key9 = 23U; const unsigned int key0 = 24U; const unsigned int keyBACKSPACE = 25U; const unsigned int keyINSERT = 26U; const unsigned int keyHOME = 27U; const unsigned int keyPAGEUP = 28U; const unsigned int keyTAB = 29U; const unsigned int keyQ = 30U; const unsigned int keyW = 31U; const unsigned int keyE = 32U; const unsigned int keyR = 33U; const unsigned int keyT = 34U; const unsigned int keyY = 35U; const unsigned int keyU = 36U; const unsigned int keyI = 37U; const unsigned int keyO = 38U; const unsigned int keyP = 39U; const unsigned int keyDELETE = 40U; const unsigned int keyEND = 41U; const unsigned int keyPAGEDOWN = 42U; const unsigned int keyCAPSLOCK = 43U; const unsigned int keyA = 44U; const unsigned int keyS = 45U; const unsigned int keyD = 46U; const unsigned int keyF = 47U; const unsigned int keyG = 48U; const unsigned int keyH = 49U; const unsigned int keyJ = 50U; const unsigned int keyK = 51U; const unsigned int keyL = 52U; const unsigned int keyENTER = 53U; const unsigned int keySHIFTLEFT = 54U; const unsigned int keyZ = 55U; const unsigned int keyX = 56U; const unsigned int keyC = 57U; const unsigned int keyV = 58U; const unsigned int keyB = 59U; const unsigned int keyN = 60U; const unsigned int keyM = 61U; const unsigned int keySHIFTRIGHT = 62U; const unsigned int keyARROWUP = 63U; const unsigned int keyCTRLLEFT = 64U; const unsigned int keyAPPLEFT = 65U; const unsigned int keySPACE = 66U; const unsigned int keyALTGR = 67U; const unsigned int keyAPPRIGHT = 68U; const unsigned int keyMENU = 69U; const unsigned int keyCTRLRIGHT = 70U; const unsigned int keyARROWLEFT = 71U; const unsigned int keyARROWDOWN = 72U; const unsigned int keyARROWRIGHT = 73U; const unsigned int keyPAD0 = 74U; const unsigned int keyPAD1 = 75U; const unsigned int keyPAD2 = 76U; const unsigned int keyPAD3 = 77U; const unsigned int keyPAD4 = 78U; const unsigned int keyPAD5 = 79U; const unsigned int keyPAD6 = 80U; const unsigned int keyPAD7 = 81U; const unsigned int keyPAD8 = 82U; const unsigned int keyPAD9 = 83U; const unsigned int keyPADADD = 84U; const unsigned int keyPADSUB = 85U; const unsigned int keyPADMUL = 86U; const unsigned int keyPADDIV = 87U; #endif const double PI = 3.14159265358979323846; //!< Definition of the mathematical constant PI // Definition of a 7x11 font, used to return a default font for drawing text. const unsigned int font7x11[7*11*256/32] = { 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x90,0x0,0x7f0000,0x40000,0x0,0x0,0x4010c0a4,0x82000040,0x11848402,0x18480050,0x80430292,0x8023,0x9008000, 0x40218140,0x4000040,0x21800402,0x18000051,0x1060500,0x8083,0x10000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x24002,0x4031,0x80000000,0x10000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c0400,0x40020000,0x80070080,0x40440e00,0x0,0x0,0x1,0x88180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x200000,0x0,0x0,0x80000,0x0,0x0,0x20212140,0x5000020,0x22400204,0x240000a0,0x40848500,0x4044,0x80010038,0x20424285,0xa000020, 0x42428204,0x2428e0a0,0x82090a14,0x4104,0x85022014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10240a7,0x88484040,0x40800000,0x270c3,0x87811e0e, 0x7c70e000,0x78,0x3c23c1ef,0x1f3e1e89,0xf1c44819,0xa23cf0f3,0xc3cff120,0xc18307f4,0x4040400,0x20000,0x80080080,0x40200,0x0, 0x40000,0x2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8188,0x50603800,0xf3c00000,0x1c004003,0xc700003e,0x18180,0xc993880,0x10204081, 0x2071ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x7d1224,0x48906048,0x0,0x4000000,0x0,0x9000,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x10240aa,0x14944080,0x23610000,0x68940,0x40831010,0x8891306,0x802044,0x44522208,0x90202088,0x40448819,0xb242890a,0x24011111, 0x49448814,0x4040a00,0xe2c3c7,0x8e3f3cb9,0xc1c44216,0xee38b0f2,0xe78f9120,0xc18507e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x101c207,0x88a04001,0x9c00000,0x2200a041,0x8200113a,0x8240,0x50a3110,0x2850a142,0x850c2081,0x2040204,0x8104592,0x142850a1, 0x42cd1224,0x4888bc48,0x70e1c387,0xe3b3c70,0xe1c38e1c,0x38707171,0xc3870e1c,0x10791224,0x48906c41,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x10003ee,0x15140080,0x21810000,0x48840,0x40851020,0x8911306,0x31fd804,0x9c522408,0x90204088,0x4045081a,0xba42890a,0x24011111, 0x49285024,0x2041b00,0x132408,0x910844c8,0x4044821b,0x7244c913,0x24041111,0x49488822,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x28204,0x85006001,0x6a414000,0x3a004043,0xc700113a,0x8245,0x50a3a00,0x2850a142,0x850c4081,0x2040204,0x81045d2,0x142850a1, 0x24951224,0x48852250,0x8102040,0x81054089,0x12244204,0x8108992,0x24489122,0x991224,0x4888b222,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x1000143,0xa988080,0x2147c01f,0x88840,0x83091c2c,0x1070f000,0xc000608,0xa48bc408,0x9e3c46f8,0x40460816,0xaa42f10b,0xc3811111, 0x35102044,0x1041100,0xf22408,0x9f084488,0x40470212,0x62448912,0x6041111,0x55308846,0x8061c80,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x1028704,0x8f805801,0x4be28fdf,0x220001f0,0x111a,0x60000182,0x82c5c710,0x44891224,0x489640f1,0xe3c78204,0x810e552,0x142850a1, 0x18a51224,0x48822250,0x78f1e3c7,0x8f1f40f9,0xf3e7c204,0x8108912,0x24489122,0x7ea91224,0x4888a222,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x10007e2,0x85648080,0x20010000,0x88841,0x8f8232,0x20881000,0xc1fc610,0xbefa2408,0x90204288,0x40450816,0xa642810a,0x4041110a, 0x36282084,0x1042080,0x1122408,0x90084488,0x40450212,0x62448912,0x184110a,0x55305082,0x8042700,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x1028207,0x82004801,0x68050040,0x1c000040,0x110a,0x60000001,0x45484d10,0x7cf9f3e7,0xcf944081,0x2040204,0x8104532,0x142850a1, 0x18a51224,0x48822248,0x89122448,0x91244081,0x2040204,0x8108912,0x24489122,0xc91224,0x48852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x282, 0x89630080,0x20010c00,0x30108842,0x810222,0x20882306,0x3001800,0x408a2208,0x90202288,0x40448814,0xa642810a,0x2041110a,0x26442104, 0x840000,0x1122408,0x90084488,0x40448212,0x62448912,0x84130a,0x36485102,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x101c208,0x4f802801, 0x8028040,0x40,0x130a,0x2,0x85e897a0,0x44891224,0x489c2081,0x2040204,0x8104532,0x142850a1,0x24cd1224,0x48823c44,0x89122448, 0x91244081,0x2040204,0x8108912,0x24489122,0xc93264,0xc9852214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100028f,0x109f0080,0x20010c00, 0x303071f3,0xc7011c1c,0x4071c306,0x802010,0x3907c1ef,0x1f201e89,0xf3844f90,0xa23c80f2,0x17810e04,0x228223f4,0x840000,0xfbc3c7, 0x8f083c88,0x40444212,0x6238f0f2,0x7039d04,0x228423e2,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1008780,0x2201800,0xf0014000,0x1f0, 0x1d0a,0x5,0x851e140,0x83060c18,0x30671ef9,0xf3e7cf9f,0x3e7c7911,0xe3c78f1e,0x42f8e1c3,0x8702205c,0x7cf9f3e7,0xcf9b3c78,0xf1e3c204, 0x8107111,0xc3870e1c,0x10f1d3a7,0x4e823c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x40,0x40000400,0x200000,0x0,0x2,0x0,0x0,0x0,0x0,0x18, 0x0,0x4,0x44007f,0x0,0x400,0x400000,0x8010,0x0,0x6002,0x8040000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x200800,0x0,0x0,0x100a, 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, 0x400000,0x0,0x4,0x0,0x0,0x0,0x0,0xc,0x0,0x7,0x3c0000,0x0,0x3800,0x3800000,0x8010,0x0,0x1c001,0x881c0000,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x207000,0x0,0x0,0x100a,0xc00000,0x3c,0x0,0xc00,0x0,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x0,0x1c2070 }; // Definition of a 10x13 font (used in dialog boxes). const unsigned int font10x13[256*10*13/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,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, 0x68000300,0x801,0xc00010,0x100c000,0x68100,0x100c0680,0x2,0x403000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x58120480,0x402,0x1205008,0x2012050,0x58080,0x20120581,0x40000001,0x804812,0x2000000,0x0,0x300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x7010,0x7000000,0x8000200,0x20000,0xc0002000,0x8008,0x0,0x0,0x0,0x0,0x808,0x4000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x80000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x80100c0,0x68000480,0x1001, 0xc00010,0x1018000,0x68100,0x100c0680,0x4,0x403000,0x1020000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140,0x28081883,0x200801, 0x2a00000,0x10,0x1c0201c0,0x70040f80,0xc0f81c07,0x0,0x70,0x3e0303c0,0x3c3c0f83,0xe03c2107,0xe08810,0x18c31070,0x3c0703c0, 0x783e0842,0x22222208,0x83e04010,0x1008000,0x4000200,0x20001,0x2002,0x408008,0x0,0x0,0x100000,0x0,0x1008,0x2000000,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20080,0x38000880,0x8078140f,0x81c00000,0x3e000,0xc020180,0x60080001,0xe0000002,0xc00042,0x108e2010, 0xc0300c0,0x300c0303,0xf83c3e0f,0x83e0f81c,0x701c070,0x3c0c41c0,0x701c0701,0xc0001d08,0x42108421,0x8820088,0x4020120,0x58140480, 0x802,0x1205008,0x3014050,0xc058080,0x20120581,0x40000002,0x804814,0x2020050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20140, 0x281e2484,0x80200801,0x1c02000,0x10,0x22060220,0x880c0801,0x82208,0x80000001,0x20008,0x41030220,0x40220802,0x402102,0x209010, 0x18c31088,0x22088220,0x80080842,0x22222208,0x80204010,0x1014000,0x200,0x20001,0x2000,0x8008,0x0,0x0,0x100000,0x0,0x1008, 0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x40000500,0x80800010,0x40200000,0x41000,0x12020040,0x10000003,0xa0000006, 0x12000c4,0x31014000,0xc0300c0,0x300c0302,0x80402008,0x2008008,0x2008020,0x220c4220,0x88220882,0x20002208,0x42108421,0x8820088, 0x0,0x300,0x0,0x0,0x0,0x14000000,0x0,0x200200,0x0,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xfc282504,0x80001000, 0x82a02000,0x20,0x22020020,0x8140802,0x102208,0x80801006,0x18008,0x9c848220,0x80210802,0x802102,0x20a010,0x15429104,0x22104220, 0x80080842,0x22221405,0x404008,0x1022000,0x703c0,0x381e0701,0xc0783c02,0xc09008,0x1d83c070,0x3c078140,0x381c0882,0x21242208, 0x81e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0,0x40220500,0x80800027,0x20e02800,0x9c800,0x12020040, 0x20000883,0xa0200002,0x120a044,0x11064010,0x12048120,0x48120484,0x80802008,0x2008008,0x2008020,0x210a4411,0x4411044,0x10884508, 0x42108421,0x503c0b0,0x1c0701c0,0x701c0707,0x70381c07,0x1c07008,0x2008020,0x20f01c0,0x701c0701,0xc0201c08,0x82208822,0x883c088, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x50281903,0x20001000,0x80802000,0x20,0x22020040,0x30240f03,0xc0101c08,0x80801018, 0x1fc06010,0xa48483c0,0x80210f03,0xe0803f02,0x20c010,0x15429104,0x22104220,0x70080841,0x41540805,0x804008,0x1041000,0x8220, 0x40220881,0x882202,0x40a008,0x12422088,0x22088180,0x40100882,0x21241408,0x80201008,0x2031000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x20280,0x401c0200,0x700028,0x21205000,0x92800,0xc1fc080,0x10000883,0xa0200002,0x1205049,0x12c19010,0x12048120,0x48120484, 0xf0803c0f,0x3c0f008,0x2008020,0x790a4411,0x4411044,0x10504908,0x42108421,0x5022088,0x2008020,0x8020080,0x88402208,0x82208808, 0x2008020,0x1e088220,0x88220882,0x20002608,0x82208822,0x8822088,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x501c0264, 0xa0001000,0x8001fc00,0x7000020,0x22020080,0x83e0082,0x20202207,0x80000020,0x1020,0xa4848220,0x80210802,0x9c2102,0x20c010, 0x12425104,0x3c1043c0,0x8080841,0x41540802,0x804008,0x1000000,0x78220,0x40220f81,0x882202,0x40c008,0x12422088,0x22088100, 0x60100881,0x41540805,0x406008,0x1849000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0xf0140200,0x880028,0x20e0a03f,0x709c800, 0x201c0,0x60000881,0xa0000007,0xc0284b,0x122eb020,0x12048120,0x48120487,0x80802008,0x2008008,0x2008020,0x21094411,0x4411044, 0x10204908,0x42108421,0x2022088,0x1e0781e0,0x781e0787,0xf8403e0f,0x83e0f808,0x2008020,0x22088220,0x88220882,0x21fc2a08,0x82208822, 0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xf80a0294,0x40001000,0x80002000,0x20,0x22020100,0x8040082,0x20202200, 0x80000018,0x1fc06020,0xa48fc220,0x80210802,0x842102,0x20a010,0x12425104,0x20104240,0x8080841,0x41541402,0x1004008,0x1000000, 0x88220,0x40220801,0x882202,0x40a008,0x12422088,0x22088100,0x18100881,0x41540805,0x801008,0x2046000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x20280,0x401c0f80,0x80880028,0x20005001,0x94800,0x20000,0x880,0xa0000000,0x5015,0x4215040,0x3f0fc3f0,0xfc3f0fc8, 0x80802008,0x2008008,0x2008020,0x21094411,0x4411044,0x10505108,0x42108421,0x203c088,0x22088220,0x88220888,0x80402008,0x2008008, 0x2008020,0x22088220,0x88220882,0x20002a08,0x82208822,0x5022050,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xa00a0494,0x60001000, 0x80002004,0x8020,0x22020200,0x88040882,0x20402201,0x801006,0x18000,0x9f084220,0x40220802,0x442102,0x209010,0x10423088,0x20088220, 0x8080840,0x80882202,0x2004008,0x1000000,0x88220,0x40220881,0x882202,0x409008,0x12422088,0x22088100,0x8100880,0x80881402, 0x1001008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20280,0x40220200,0x80700027,0x20002801,0x92800,0x1fc000,0x980, 0xa0000000,0xa017,0x84417840,0x21084210,0x84210848,0x80402008,0x2008008,0x2008020,0x2208c220,0x88220882,0x20882208,0x42108421, 0x2020088,0x22088220,0x88220888,0xc8402208,0x82208808,0x2008020,0x22088220,0x88220882,0x20203208,0x82208822,0x2022020,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0xa03c0463,0x90000801,0x2004,0x8040,0x1c0703e0,0x70040701,0xc0401c06,0x801001,0x20020, 0x400843c0,0x3c3c0f82,0x3c2107,0x1c0881e,0x10423070,0x20070210,0xf0080780,0x80882202,0x3e04004,0x1000000,0x783c0,0x381e0701, 0x782202,0x408808,0x12422070,0x3c078100,0x700c0780,0x80882202,0x1e01008,0x2000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x201e0, 0xf8000200,0x80080010,0x40000001,0x41000,0x0,0xe80,0xa0000000,0x21,0x8e21038,0x21084210,0x84210848,0xf83c3e0f,0x83e0f81c, 0x701c070,0x3c08c1c0,0x701c0701,0xc0005c07,0x81e0781e,0x20200b0,0x1e0781e0,0x781e0787,0x30381c07,0x1c07008,0x2008020,0x1c0881c0, 0x701c0701,0xc0201c07,0x81e0781e,0x203c020,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000,0x801,0x4,0x40,0x0,0x0,0x0,0x1000, 0x0,0x3c000000,0x0,0x0,0x0,0x0,0x10000,0x0,0x0,0x4004,0x1000000,0x0,0x0,0x80000,0x400000,0x0,0x20008000,0x0,0x4,0x1008,0x2000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x8008000f,0x80000000,0x3e000,0x0,0x800,0xa0000400,0x0,0x0,0x0,0x0,0x80000,0x0, 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, 0x402,0x8,0x40,0x0,0x0,0x0,0x2000,0x0,0x0,0x0,0x0,0x0,0x0,0xc000,0x0,0x0,0x7004,0x70000fc,0x0,0x0,0x700000,0x800000,0x0,0x20008000, 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, 0x300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x4020040 }; // Definition of a 8x17 font const unsigned int font8x17[8*17*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x2400,0x2400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20081834,0x1c0000,0x20081800,0x20081800,0x342008, 0x18340000,0x200818,0x80000,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4200000,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x380000,0x4000,0x2000c00,0x40100840,0x70000000,0x0,0x0,0x1c,0x10700000,0x7,0x0, 0x1800,0x1800,0x0,0x0,0x0,0x14,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1010242c,0x14140000,0x10102414,0x10102414,0x2c1010,0x242c1400, 0x101024,0x14100038,0x0,0x240000,0x0,0x0,0x30000000,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x12,0x0,0x8100000,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x80000,0x10004000,0x2001000,0x40000040,0x10000000,0x0,0x0,0x10,0x10100000,0x4, 0x0,0x18000000,0x0,0x0,0x0,0x34002400,0x2400,0x0,0x0,0x0,0x3c,0x0,0x8000000,0x0,0x60607800,0x0,0x140000,0x0,0x0,0x0,0x0,0x0, 0x44,0x10081834,0x240000,0x10081800,0x10081800,0x1c341008,0x18340000,0x100818,0x84000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102812, 0x8601c10,0x8100800,0x2,0x1c383e3e,0x67e1e7f,0x3e3c0000,0x38,0x1e087e1e,0x7c7f7f1e,0x417c1c42,0x4063611c,0x7e1c7e3e,0xfe414181, 0x63827f10,0x40081000,0x8004000,0x2001000,0x40000040,0x10000000,0x0,0x10000000,0x10,0x10100000,0x3c000008,0x0,0x24003e00, 0x3f007f00,0x0,0x0,0x2ce91800,0x1882,0x10101c,0xc2103c,0x143c3c00,0x3c00,0x18003c3c,0x10001f00,0x181c00,0x20200810,0x8080808, 0x8083e1e,0x7f7f7f7f,0x7c7c7c7c,0x7c611c1c,0x1c1c1c00,0x1e414141,0x41824044,0x810242c,0x14180000,0x8102414,0x8102414,0x382c0810, 0x242c1400,0x81024,0x14104014,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102816,0x3e902010,0x10084910,0x4,0x22084343,0xa402102,0x41620000, 0x44,0x33144121,0x42404021,0x41100444,0x40636122,0x43224361,0x10416381,0x22440310,0x20082800,0x4000,0x2001000,0x40000040, 0x10000000,0x0,0x10000000,0x10,0x10100000,0x24000008,0x0,0x606100,0x68000300,0x8106c,0x34000000,0x4f0000,0x44,0x101020,0x441040, 0x420200,0x4200,0x24000404,0x7d00,0x82200,0x20203010,0x14141414,0x14082821,0x40404040,0x10101010,0x42612222,0x22222200,0x23414141, 0x41447e48,0x0,0x0,0x0,0x0,0x4000000,0x18,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10287f,0x49902010,0x10083e10,0x4,0x41080101, 0x1a404002,0x41411818,0x1004004,0x21144140,0x41404040,0x41100448,0x40555141,0x41414140,0x10412281,0x14280610,0x20084400,0x1c7c1c, 0x3e3c7c3a,0x5c703844,0x107f5c3c,0x7c3e3c3c,0x7e424281,0x66427e10,0x10100000,0x40100008,0x1010,0xa04000,0x48100610,0x100c3024, 0x24000000,0x4f3c00,0x2c107e28,0x3820,0x42281060,0x9d1e12,0xbd00,0x24100818,0x427d00,0x82248,0x20200800,0x14141414,0x14142840, 0x40404040,0x10101010,0x41514141,0x41414142,0x43414141,0x41284350,0x1c1c1c1c,0x1c1c6c1c,0x3c3c3c3c,0x70707070,0x3c5c3c3c, 0x3c3c3c18,0x3e424242,0x42427c42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x102824,0x48623010,0x10081c10,0x8,0x41080103,0x127c5e04, 0x41411818,0xe7f3808,0x4f144140,0x41404040,0x41100450,0x40555141,0x41414160,0x1041225a,0x1c280410,0x1008c600,0x226622,0x66661066, 0x62100848,0x10496266,0x66663242,0x10426681,0x24220260,0x100c0000,0xf8280008,0x1010,0x606000,0x48280428,0x28042014,0x48000000, 0x494200,0x52280228,0x105420,0x3cee1058,0xa12236,0xa500,0x18101004,0x427d00,0x8226c,0x76767e10,0x14141414,0x14142840,0x40404040, 0x10101010,0x41514141,0x41414124,0x45414141,0x41284150,0x22222222,0x22221222,0x66666666,0x10101010,0x66626666,0x66666600, 0x66424242,0x42226622,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100024,0x381c4900,0x10086bfe,0x8,0x4908021c,0x22036304,0x3e630000, 0x70000710,0x51227e40,0x417f7f43,0x7f100470,0x40554941,0x43417e3e,0x1041225a,0x8100810,0x10080000,0x24240,0x42421042,0x42100850, 0x10494242,0x42422040,0x1042245a,0x18240410,0x10103900,0x407c003e,0x1818,0x1c3e10,0x4f7c087c,0x7c002010,0x48000000,0x4008, 0x527c0410,0x105078,0x2410104c,0xa13e6c,0x7f00b900,0xfe3c3c,0x421d18,0x1c1c36,0x38383810,0x22222222,0x22144e40,0x7f7f7f7f, 0x10101010,0xf1494141,0x41414118,0x49414141,0x4110435c,0x2020202,0x2021240,0x42424242,0x10101010,0x42424242,0x424242ff,0x4e424242, 0x42244224,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000fe,0xe664d00,0x10080810,0x380010,0x41080c03,0x42014108,0x633d0000,0x70000710, 0x51224140,0x41404041,0x41100448,0x40494541,0x7e414203,0x1041145a,0x14101010,0x10080000,0x3e4240,0x427e1042,0x42100870,0x10494242, 0x4242203c,0x1042245a,0x18241810,0x10104600,0xf8f60008,0x1010,0x600320,0x48f610f6,0xf6000000,0x187eff,0x3c04,0x5ef61810,0x105020, 0x24fe0064,0x9d006c,0x138ad00,0x100000,0x420518,0x36,0xc0c0c020,0x22222222,0x22224840,0x40404040,0x10101010,0x41454141,0x41414118, 0x51414141,0x41107e46,0x3e3e3e3e,0x3e3e7e40,0x7e7e7e7e,0x10101010,0x42424242,0x42424200,0x5a424242,0x42244224,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x28,0x9094500,0x10080010,0x10,0x41081801,0x7f014118,0x41010000,0xe7f3800,0x513e4140,0x41404041,0x41100444, 0x40414541,0x40414101,0x10411466,0x36103010,0x8080000,0x424240,0x42401042,0x42100848,0x10494242,0x42422002,0x10423c5a,0x18142010, 0x10100000,0x407c0010,0x1010,0x260140,0x487c307c,0x7c000000,0x180000,0x202,0x507c2010,0x105020,0x3c10003c,0x423e36,0x1004200, 0x100000,0x420500,0x3e6c,0x41e0440,0x3e3e3e3e,0x3e3e7840,0x40404040,0x10101010,0x41454141,0x41414124,0x61414141,0x41104042, 0x42424242,0x42425040,0x40404040,0x10101010,0x42424242,0x42424218,0x72424242,0x42144214,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048, 0x49096200,0x8100010,0x18001810,0x22082043,0x2432310,0x61421818,0x1004010,0x4f634121,0x42404021,0x41104444,0x40414322,0x40234143, 0x10411466,0x22106010,0x8080000,0x466622,0x66621066,0x42100844,0x10494266,0x66662042,0x10461824,0x24184010,0x10100000,0x24381010, 0x34001018,0xda4320,0x68386038,0x38000000,0x0,0x4204,0x50384010,0x105420,0x4210100c,0x3c0012,0x3c00,0x0,0x460500,0x48,0xc020c44, 0x63636363,0x63228821,0x40404040,0x10101010,0x42432222,0x22222242,0x62414141,0x41104042,0x46464646,0x46465022,0x62626262, 0x10101010,0x66426666,0x66666618,0x66464646,0x46186618,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100048,0x3e063d00,0x8100000,0x18001820, 0x1c3e7f3e,0x23c1e20,0x3e3c1818,0x10,0x20417e1e,0x7c7f401e,0x417c3842,0x7f41431c,0x401e40be,0x103e0866,0x41107f10,0x4080000, 0x3a5c1c,0x3a3c103a,0x427c0842,0xe49423c,0x7c3e203c,0xe3a1824,0x66087e10,0x10100000,0x3c103010,0x245a1010,0x5a3e10,0x3f107f10, 0x10000000,0x0,0x3c08,0x2e107e10,0x1038fc,0x101004,0x0,0x0,0xfe0000,0x7f0500,0x0,0x14041438,0x41414141,0x41418e1e,0x7f7f7f7f, 0x7c7c7c7c,0x7c431c1c,0x1c1c1c00,0xbc3e3e3e,0x3e10405c,0x3a3a3a3a,0x3a3a6e1c,0x3c3c3c3c,0x7c7c7c7c,0x3c423c3c,0x3c3c3c00, 0x7c3a3a3a,0x3a087c08,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x4200000,0x10000020,0x0,0x0,0x10,0x0,0x30000000,0x0, 0x0,0x0,0x60000,0x0,0x1c,0x4380000,0x0,0x2,0x800,0x0,0x40020000,0x0,0x8000c,0x10600000,0x2010,0x48000000,0x240000,0x0,0x0, 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, 0x84008,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8000000,0x0,0x20000040,0x0,0x0,0x20,0x0,0x1e000000,0x0,0x0,0x0,0x20000,0x0, 0x0,0x2000000,0x0,0x26,0x800,0x0,0x40020000,0x0,0x100000,0x10000000,0x2030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000,0x1000,0x0, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 10x19 font const unsigned int font10x19[10*19*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x180181c0,0xe81b0300,0x1801,0x81c06c18,0x181c06c,0xe8180,0x181c0e81,0xb0000006,0x60701b,0x1800000,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0xc030360,0xb81b0480,0xc03,0x3606c0c,0x303606c,0xb80c0,0x30360b81,0xb0000003,0xc0d81b,0x3000000,0x0, 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, 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, 0x22000,0x0,0x0,0x0,0x0,0x0,0x0,0x30000,0x0,0xe0,0x38078000,0x0,0x480,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3000c080,0x480,0x3000, 0xc0800030,0xc08000,0x300,0xc080000,0xc,0x302000,0xc00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x41c01,0xe020060c, 0x800000,0x4,0x1e0703e0,0xf8060fc1,0xe1fe1e07,0x80000000,0x78,0x307e0,0x3c7c1fe7,0xf83c408f,0x80f10440,0x18660878,0x7e0787e0, 0x78ff9024,0xa0140a0,0x27f83840,0x700e000,0x18000400,0x8000,0x70004002,0x410078,0x0,0x0,0x0,0x0,0x1808,0xc000000,0xf000000, 0xe000000,0x1400,0x1e0001f,0x8007f800,0x0,0x0,0x3a3b,0x61400000,0x14202,0x20000,0x38002020,0x3c1b00,0x3e00000,0xf8,0x1c0001c0, 0x78060001,0xf800000e,0x1e00020,0x8004020,0xc0300c0,0x300c0301,0xf83c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1821e0,0x781e0781,0xe0001f10, 0x24090240,0xa02400f8,0x18018140,0xe81b0480,0x1801,0x81406c18,0x181406c,0x190e8180,0x18140e81,0xb0000006,0x60501b,0x184006c, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x26042202,0x200c06,0x800000,0x8,0x210d0611,0x40e0803,0x10026188,0x40000000, 0x8c,0xf030418,0xc6431004,0xc64082,0x110840,0x18660884,0x41084410,0x8c081024,0xa012110,0x40082020,0x101b000,0xc000400,0x8000, 0x80004002,0x410008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x18800000,0x10000000,0x2200,0x2300024,0x800,0x0,0x0,0x2e13,0x60800000, 0x8104,0x20040,0x64001040,0x80401b07,0x80100000,0x1e000,0x22000020,0x40c0003,0xc8000002,0x3300020,0x8004020,0xc0300c0,0x300c0301, 0x40c64010,0x4010008,0x2008020,0x43182210,0x84210842,0x10002190,0x24090240,0x9044018c,0xc030220,0xb81b0300,0xc03,0x2206c0c, 0x302206c,0x1e0b80c0,0x30220b81,0xb0000003,0xc0881b,0x304006c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x241f2202, 0x200802,0x4900000,0x8,0x21010408,0x20a0802,0x44090,0x20000000,0x4,0x11878408,0x80411004,0x804082,0x111040,0x1ce50986,0x40986409, 0x81022,0x12012108,0x80102020,0x1031800,0x400,0x8000,0x80004000,0x10008,0x0,0x0,0x100000,0x0,0x2008,0x2000000,0x10000000, 0x10000000,0x18,0x4000044,0x1000,0x30180,0xd81b0000,0x13,0xe0000000,0x88,0x40,0x400018c0,0x80400018,0x61f00000,0x61800,0x22020020, 0x4000007,0xc8000002,0x2100020,0x8038000,0x1e0781e0,0x781e0301,0x40804010,0x4010008,0x2008020,0x41142619,0x86619866,0x18002190, 0x24090240,0x8887e104,0x0,0x0,0x0,0x0,0x0,0x2000000,0x0,0x0,0x0,0x40000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20120,0x2434a202, 0x200802,0x3e00000,0x10,0x40810008,0x21a0804,0x44090,0x20000000,0x80040004,0x20848409,0x409004,0x1004082,0x112040,0x14a50902, 0x40902409,0x81022,0x11321208,0x80202010,0x1060c00,0x7c5e0,0x781e8783,0xf07a5f0e,0x1c10808,0xfc5f078,0x5e07a170,0x7c7e1024, 0xa016190,0x27f82008,0x2000000,0x20000000,0x10000000,0x80200024,0x4000044,0x2000,0x18180,0xc8320000,0x12,0xa1f00037,0x7f888, 0x1e0,0x40410880,0x80600017,0xa2100000,0x5e800,0x22020040,0x38001027,0xc8000002,0x2100020,0x8004020,0x12048120,0x48120482, 0x41004010,0x4010008,0x2008020,0x40942409,0x2409024,0x9044390,0x24090240,0x88841918,0x1f07c1f0,0x7c1f07c3,0x70781e07,0x81e07838, 0xe0380e0,0x1f17c1e0,0x781e0781,0xe0001f90,0x24090240,0x9025e102,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0xff241c41, 0x1001,0x1c02000,0x10,0x40810008,0x6120f85,0xe0086190,0x20c03007,0x8007800c,0x27848419,0x409004,0x1004082,0x114040,0x14a48902, 0x40902409,0x81022,0x11321205,0x602010,0x1000000,0x86610,0x84218840,0x80866182,0x411008,0x9261884,0x61086189,0x82101022,0x12012108, 0x40082008,0x2000000,0x20030000,0x20000000,0x80200024,0x4000044,0x3006030,0xc018100,0x4c260000,0x12,0x26080048,0x83000850, 0x20250,0x403e0500,0x8078002c,0x12302200,0x92400,0x1c0200c0,0x4001027,0xc8000002,0x3308820,0x8004020,0x12048120,0x48120482, 0x41004010,0x4010008,0x2008020,0x40922409,0x2409024,0x8884690,0x24090240,0x85040920,0x21886218,0x86218860,0x88842108,0x42108408, 0x2008020,0x21186210,0x84210842,0x10302190,0x24090240,0x88461084,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x4c240182, 0x80001001,0x6b02000,0x20,0x4c810010,0x78220846,0x10081e10,0x20c0301c,0x1fe0e018,0x4d8487e1,0x409fe7,0xf9007f82,0x11a040, 0x13248902,0x41102418,0xe0081022,0x11320c05,0x402008,0x1000000,0x2409,0x409020,0x81024082,0x412008,0x9240902,0x40902101,0x101022, 0x11321208,0x40102008,0x2000000,0x7e0c8000,0xfc000003,0xf0fc0018,0x43802047,0x8c8040c8,0x32008300,0x44240000,0x0,0x4000048, 0x8c801050,0x20440,0x40221dc0,0x808c0028,0x11d0667f,0x8009c400,0x1fc180,0x4001023,0xc8300002,0x1e0ccfb,0x3ec7b020,0x12048120, 0x48120482,0x79007f9f,0xe7f9fe08,0x2008020,0xf0922409,0x2409024,0x8504490,0x24090240,0x85040920,0x802008,0x2008020,0x89004090, 0x24090208,0x2008020,0x40902409,0x2409024,0x8304390,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000, 0x481c0606,0xc8001001,0x802000,0x20,0x4c810020,0x4220024,0x8102108,0x60000070,0x3820,0x48884419,0x409004,0x10e4082,0x112040, 0x13244902,0x7e1027e0,0x3c081021,0x21320c02,0x802008,0x1000000,0x7e409,0x409020,0x81024082,0x414008,0x9240902,0x40902101, 0x80101022,0x11320c08,0x40202008,0x2038800,0x200bc000,0x20000000,0x80200003,0x80f04044,0xbc080bc,0x2f000200,0x0,0x0,0x6001048, 0x8bc02020,0x20441,0xf8220200,0x80820028,0x1000cc00,0x80094400,0x201e0,0x78001021,0xc830000f,0x8000663c,0xf03c0c0,0x21084210, 0x84210846,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8204890,0x24090240,0x82040930,0x1f87e1f8,0x7e1f87e0,0x89004090, 0x24090208,0x2008020,0x40902409,0x2409024,0x8004690,0x24090240,0x88440884,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000, 0x480719c4,0x48001001,0x81fc00,0x7800020,0x40810040,0x2420024,0x8104087,0xa0000070,0x3820,0x48884409,0x409004,0x1024082,0x111040, 0x13244902,0x40102410,0x2081021,0x214a1202,0x1802008,0x1000000,0x182409,0x409fe0,0x81024082,0x41a008,0x9240902,0x40902100, 0xf8101021,0x214a0c04,0x80c0c008,0x1847000,0x7c1ee000,0x20000000,0x8020000c,0x8c044,0x1ee181ee,0x7b800000,0x707,0xf3ff0000, 0x3e0084f,0x9ee0c020,0x20440,0x40221fc0,0xc2002c,0x13f11000,0x87892400,0x20000,0x1020,0x48000000,0x3f011c6,0x31cc6180,0x21084210, 0x84210844,0x41004010,0x4010008,0x2008020,0x40912409,0x2409024,0x8505090,0x24090240,0x8204191c,0x60982609,0x82609823,0xf9007f9f, 0xe7f9fe08,0x2008020,0x40902409,0x2409024,0x9fe4c90,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0xfe048224, 0x28001001,0x2000,0x40,0x40810080,0x27f8024,0x8104080,0x2000001c,0x1fe0e020,0x488fc409,0x409004,0x1024082,0x110840,0x10242902, 0x40102408,0x2081021,0x214a1202,0x1002004,0x1000000,0x102409,0x409000,0x81024082,0x411008,0x9240902,0x40902100,0x6101021, 0x214a0c04,0x81002008,0x2000000,0x201dc000,0x20000000,0x80200000,0x98044,0x1dc101dc,0x77000000,0x700,0x0,0x180448,0x1dc10020, 0x20440,0x403e0200,0x620017,0xa000cc00,0x80052800,0x20000,0x1020,0x48000000,0x6606,0x206100,0x3f0fc3f0,0xfc3f0fc7,0xc1004010, 0x4010008,0x2008020,0x4090a409,0x2409024,0x8886090,0x24090240,0x8207e106,0x40902409,0x2409024,0x81004010,0x4010008,0x2008020, 0x40902409,0x2409024,0x8005890,0x24090240,0x84840848,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98048224,0x30001001,0x2000, 0x40,0x21010100,0x2020024,0x8204080,0x40000007,0x80078000,0x48884408,0x80411004,0x824082,0x110840,0x10242986,0x40086409,0x2081021, 0xe14a2102,0x2002004,0x1000000,0x106409,0x409000,0x81024082,0x410808,0x9240902,0x40902100,0x2101021,0x214a1202,0x82002008, 0x2000000,0x300f8000,0x20000000,0x80fc001d,0xe4088044,0xf8200f8,0x3e000000,0x300,0x0,0x80c48,0xf820020,0x20640,0x40410200, 0x803c0018,0x60006600,0x61800,0x0,0x1020,0x48000000,0xcc0a,0x20a100,0x21084210,0x84210844,0x40804010,0x4010008,0x2008020, 0x4110a619,0x86619866,0x19046110,0x24090240,0x82040102,0x41906419,0x6419064,0x81004010,0x4010008,0x2008020,0x40902409,0x2409024, 0x8307090,0x24090240,0x82840828,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20000,0x90248222,0x30000802,0x200c,0xc080,0x21010301, 0x4021042,0x10202108,0xc0c03000,0x80040020,0x4d902418,0xc6431004,0xc24082,0x6210440,0x10241884,0x40084409,0x86080840,0xc0842102, 0x4002002,0x1000000,0x18e610,0x84218820,0x80864082,0x410408,0x9240884,0x61086101,0x6101860,0xc0842103,0x4002008,0x2000000, 0x10850180,0x20330000,0x80200013,0x26184024,0x5040050,0x14000000,0x0,0x0,0x4180848,0x85040020,0x20350,0x40000200,0x800c0007, 0x80002200,0x1e000,0x0,0x1860,0x48000000,0x880a,0x40a188,0x40902409,0x2409028,0x40c64010,0x4010008,0x2008020,0x43106210,0x84210842, 0x10006108,0x42108421,0x2040102,0x6398e639,0x8e6398e4,0x88842088,0x22088208,0x2008020,0x21102210,0x84210842,0x10306118,0x66198661, 0x83061030,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20001,0x901f01c1,0xe8000802,0xc,0xc080,0x1e07c7f8,0xf8020f81,0xe0401e07, 0x80c03000,0x20,0x279027e0,0x3c7c1fe4,0x3c408f,0x83c1027f,0x90241878,0x4007c404,0xf8080780,0xc0844082,0x7f82002,0x1000000, 0xfa5e0,0x781e87c0,0x807a409f,0xc0410207,0x9240878,0x5e07a100,0xf80e0fa0,0xc0846183,0x7f82008,0x2000000,0xf020100,0x40321360, 0x80200014,0xa3e0201f,0x8207f820,0x8000000,0x0,0x0,0x3e01037,0x207f820,0x201e1,0xfc000200,0x80040000,0x0,0x0,0x1fc000,0x17b0, 0x48000000,0x12,0xc120f0,0x40902409,0x2409028,0x783c7f9f,0xe7f9fe3e,0xf83e0f8,0x7c1061e0,0x781e0781,0xe000be07,0x81e0781e, 0x204017c,0x3e8fa3e8,0xfa3e8fa3,0x70781f07,0xc1f07c7f,0x1fc7f1fc,0x1e1021e0,0x781e0781,0xe0007e0f,0xa3e8fa3e,0x8305e030,0x0, 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, 0x0,0x0,0x2001,0x1000000,0x0,0x0,0x20000,0x400000,0x0,0x40002000,0x0,0x1,0x2008,0x2000000,0x100,0x40240000,0x80200008,0x40000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80040000,0x0,0x0,0x0,0x1000,0x48000000,0x1f,0x181f000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x6000,0x0,0x10000000,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x3800,0x7000000,0x0,0x0,0x840000,0x400000,0x0,0x40002000, 0x0,0x2,0x2008,0x2000000,0x200,0x40440000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x80780000,0x0,0x0,0x0,0x1000,0x48000400, 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, 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, 0x780000,0x3800000,0x0,0x40002000,0x0,0xe,0x1808,0xc000000,0x3,0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80000000, 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, 0x0,0x0,0x0,0x0,0x0,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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 12x24 font const unsigned int font12x24[12*24*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc001806,0xc81980,0x60000000,0xc001806,0x1980c00,0x18060198,0xc80c, 0x180600,0xc8198000,0xc001,0x80601980,0x18000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x600300f,0x1301980,0x90000000,0x600300f,0x1980600,0x300f0198,0x13006,0x300f01,0x30198000,0x6003, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x80000000,0x90000000,0x3006019,0x80000300,0x60198000,0x3,0x601980,0x0,0x3006,0x1980000,0x60000000,0x0,0x0,0xe0000000,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0xc800019,0x80000000,0x198000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc0,0x0,0x0,0x1001,0x420000,0x0,0x0,0x90000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18000c06,0xc80001,0x10000000,0x18000c06,0x1800,0xc060000,0xc818,0xc0600,0xc8000000, 0x18000,0xc0600000,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80660207,0x800f8060,0x300c004,0x0,0x6, 0xe00703f,0x3f00383,0xf80f07fc,0x1f01f000,0x0,0xf8,0x607f,0x7c7e07,0xfe7fe0f8,0x6063fc1f,0x86066007,0xe7060f0,0x7f80f07f, 0x81f8fff6,0x6606c03,0x70ee077f,0xe0786000,0xf0070000,0xc000060,0xc0,0x3e000,0x60006003,0x600fc00,0x0,0x0,0x0,0x0,0x0,0x3c0603, 0xc0000000,0x7800000,0xf0000,0x0,0xf00001f,0x80001fe0,0x7fe000,0x0,0x0,0x0,0x168fe609,0x0,0x90e07,0x6000,0x3c000e,0x70000f8, 0x1980001f,0x0,0x1f8,0xf00000f,0xf00180,0xfe000,0xe00e,0x1001,0x20060,0x6006006,0x600600,0x600fe07c,0x7fe7fe7f,0xe7fe3fc3, 0xfc3fc3fc,0x7e07060f,0xf00f00,0xf00f0000,0xf360660,0x6606606e,0x76001e0,0xc00180f,0x1681981,0x10000000,0xc00180f,0x1980c00, 0x180f0198,0x3801680c,0x180f01,0x68198000,0xc001,0x80f01980,0x18600198,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019, 0x8044020c,0xc01f8060,0x2004004,0x0,0xc,0x3f81f07f,0x87f80383,0xf81f87fc,0x3f83f800,0x0,0x1fc,0x780607f,0x81fe7f87,0xfe7fe1fc, 0x6063fc1f,0x860c6007,0xe7061f8,0x7fc1f87f,0xc3fcfff6,0x6606c03,0x30c6067f,0xe0783000,0xf00d8000,0x6000060,0xc0,0x7e000,0x60006003, 0x600fc00,0x0,0x0,0xc00,0x0,0x0,0x7c0603,0xe0000000,0xfc00000,0x1f0000,0x0,0x900003f,0xc0003fe0,0x7fe000,0x0,0x0,0x0,0x1302660f, 0x0,0xf0606,0x6004,0x7e0006,0x60601f8,0x19800001,0x80000000,0x1f8,0x19800010,0x81080300,0x3f2000,0x2011,0x1001,0x1c0060,0x6006006, 0x600600,0x601fe1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f87061f,0x81f81f81,0xf81f8000,0x3fa60660,0x66066066,0x66003f0,0x6003009, 0x1301981,0x10000000,0x6003009,0x1980600,0x30090198,0x1f013006,0x300901,0x30198000,0x6003,0x901980,0x30600198,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc0f8c,0xc0180060,0x6006044,0x40000000,0xc,0x3181b041,0xc41c0783,0x388018, 0x71c71800,0x0,0x106,0x18c0f061,0xc38261c6,0x600384,0x60606001,0x86186007,0xe78630c,0x60e30c60,0xe7040606,0x630cc03,0x39c30c00, 0xc0603000,0x3018c000,0x3000060,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600,0x60000000,0x18400000,0x180000, 0x0,0x19800070,0x40003600,0xc000,0x0,0x0,0x0,0x25a06,0x0,0x6030c,0x4,0xe20007,0xe060180,0xf000,0x80000000,0xf0000,0x10800000, 0x80080600,0x7f2000,0x2020,0x80001001,0x20000,0xf00f00f,0xf00f00,0x601b0382,0x60060060,0x6000600,0x60060060,0x61c78630,0xc30c30c3, 0xc30c000,0x30e60660,0x66066063,0xc600738,0x3006019,0x80000000,0xe0000000,0x3006019,0x80000300,0x60198000,0x3e000003,0x601980, 0x0,0x3006,0x1980000,0x60600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x80cc1fcc,0xc0180060,0x6006035,0x80000000, 0x18,0x71c03000,0xc00c0583,0x300018,0x60c60c00,0x0,0x6,0x3060f060,0xc30060c6,0x600300,0x60606001,0x86306007,0x9e78670e,0x60670e60, 0x66000606,0x630c606,0x19830c01,0xc0601800,0x30306000,0x60,0xc0,0x60000,0x60000000,0x6000c00,0x0,0x0,0xc00,0x0,0x0,0x600600, 0x60000000,0x18000000,0x300000,0x0,0x78060,0x6600,0x1c000,0x300c,0x39819c0,0x0,0x25a00,0x0,0x30c,0x4,0xc00003,0xc060180,0x30c1f, 0x80000000,0x30c000,0x10800001,0x80700000,0x7f2000,0x2020,0x80001001,0x20060,0xf00f00f,0xf00f00,0xf01b0300,0x60060060,0x6000600, 0x60060060,0x60c78670,0xe70e70e7,0xe70e000,0x70c60660,0x66066063,0xc7f8618,0x0,0x0,0x0,0x0,0x0,0x0,0x7000000,0x0,0x0,0x0, 0x0,0x600000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6019,0x87ff3a4c,0xc0180060,0x400600e,0x600000,0x18,0x60c03000, 0xc00c0d83,0x700018,0x60c60c00,0x20,0x400006,0x3060f060,0xc6006066,0x600600,0x60606001,0x86606006,0x966c6606,0x60660660,0x66000606, 0x630c666,0xf019801,0x80601800,0x30603000,0x1f06f,0xf01ec0,0xf03fe1ec,0x6703e01f,0x61c0c06,0xdc6701f0,0x6f01ec0c,0xe1f87fc6, 0xc60cc03,0x71c60c7f,0xc0600600,0x60000000,0x30000000,0x300000,0x40040,0x88060,0x6600,0x18000,0x300c,0x1981980,0x0,0x2421f, 0x80003ce0,0x7fc198,0x601f,0xc02021,0x980600c0,0x40230,0x80000000,0x402000,0x19806003,0x80006,0xc7f2000,0x2020,0x80001001, 0x420060,0xf00f00f,0xf00f00,0xf01b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x6606208,0x60e60660,0x66066061, 0x987fc670,0x1f01f01f,0x1f01f01,0xf039c0f0,0xf00f00f,0xf03e03,0xe03e03e0,0x1f06701f,0x1f01f01,0xf01f0060,0x1e660c60,0xc60c60c6, 0xc6f060c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x7ff3207,0x8c0c0000,0xc00300e,0x600000,0x30,0x60c03000, 0xc01c0983,0xf0600030,0x31860c06,0x6001e0,0x78000e,0x23e1f861,0xc6006066,0x600600,0x60606001,0x86c06006,0x966c6606,0x60660660, 0xe7000606,0x630c666,0xf01f803,0x600c00,0x30000000,0x3f87f,0x83f83fc3,0xf83fe3fc,0x7f83e01f,0x6380c07,0xfe7f83f8,0x7f83fc0d, 0xf3fc7fc6,0xc71cc03,0x3183187f,0xc0600600,0x60000000,0xff806000,0x300000,0x40040,0x88070,0x6600,0x60030060,0x6001818,0x1883180, 0x0,0x2423f,0xc0007ff0,0x607fc1f8,0x603f,0x80c01fc1,0xf80601e0,0x5f220,0x80420000,0x5f2000,0xf006006,0x80006,0xc7f2000,0x2020, 0x82107c07,0xc03c0060,0x1f81f81f,0x81f81f80,0xf03b0600,0x60060060,0x6000600,0x60060060,0x6066c660,0x66066066,0x660671c,0x61660660, 0x66066061,0xf860e6c0,0x3f83f83f,0x83f83f83,0xf87fe3f8,0x3f83f83f,0x83f83e03,0xe03e03e0,0x3f87f83f,0x83f83f83,0xf83f8060, 0x3fc60c60,0xc60c60c3,0x187f8318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x883200,0x300c0000,0xc003035,0x80600000, 0x30,0x66c03001,0xc0f81983,0xf86f0030,0x1f071c06,0x600787,0xfe1e001c,0x6261987f,0x86006067,0xfe7fc600,0x7fe06001,0x87c06006, 0xf6646606,0x60e6067f,0xc3e00606,0x61986f6,0x600f007,0x600c00,0x30000000,0x21c71,0x830831c3,0x1c06031c,0x71c06003,0x6700c06, 0x6671c318,0x71831c0f,0x16040c06,0xc318606,0x1b031803,0x80600600,0x60000000,0x30009000,0x300000,0x40040,0x7003e,0x67e0,0x90070090, 0x9001818,0x8c3100,0x0,0x60,0x4000e730,0x900380f0,0x6034,0x80c018c7,0xfe060338,0xb0121,0x80c60000,0x909000,0x6008,0x1080006, 0xc3f2000,0x2011,0x3180060,0x60060e0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0x60664660,0x66066066, 0x66063b8,0x62660660,0x66066060,0xf06066c0,0x21c21c21,0xc21c21c2,0x1c466308,0x31c31c31,0xc31c0600,0x60060060,0x31871c31,0x83183183, 0x18318000,0x71860c60,0xc60c60c3,0x18718318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1981a00,0xe03e0000,0xc003044, 0x40600000,0x60,0x66c03001,0x80f03182,0x1c7f8030,0x3f83fc06,0x601e07,0xfe078038,0x6661987f,0x86006067,0xfe7fc61e,0x7fe06001, 0x87e06006,0x66666606,0x7fc6067f,0x81f80606,0x61986f6,0x6006006,0x600600,0x30000000,0xc60,0xc60060c6,0xc06060c,0x60c06003, 0x6e00c06,0x6660c60c,0x60c60c0e,0x6000c06,0xc318666,0x1f031803,0x600600,0x603c2000,0x30016800,0x1fe0000,0x1f81f8,0x1c1f,0x804067e1, 0x68060168,0x16800810,0xc42300,0x0,0x60,0x20c331,0x68030060,0x6064,0x3fc1040,0xf006031c,0xa011e,0x818c7fe0,0x909000,0x7fe1f, 0x80f00006,0xc0f2060,0xf80e,0x18c0780,0x780781c0,0x19819819,0x81981981,0x9833c600,0x7fe7fe7f,0xe7fe0600,0x60060060,0xfc666660, 0x66066066,0x66061f0,0x66660660,0x66066060,0x606066e0,0xc00c00,0xc00c00c0,0xc066600,0x60c60c60,0xc60c0600,0x60060060,0x60c60c60, 0xc60c60c6,0xc60c000,0x61c60c60,0xc60c60c3,0x1860c318,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x1980f81,0x80373000, 0xc003004,0x7fe0001,0xf0000060,0x60c03003,0x183180,0xc71c060,0x3181ec00,0x7000,0xe070,0x66619860,0xc6006066,0x60061e,0x60606001, 0x87606006,0x66626606,0x7f860661,0xc01c0606,0x6198696,0xf00600e,0x600600,0x30000000,0x1fc60,0xc60060c7,0xfc06060c,0x60c06003, 0x7c00c06,0x6660c60c,0x60c60c0c,0x7f00c06,0xc3b8666,0xe01b007,0x3c00600,0x3c7fe000,0xff03ec00,0x1fe0000,0x40040,0xe001,0xc0806603, 0xec0e03ec,0x3ec00010,0x0,0x60000000,0x7f,0x10c3f3,0xec070060,0x6064,0x3fc1040,0x6000030c,0xa0100,0x3187fe1,0xf09f1000,0x7fe00, 0x6,0xc012060,0x0,0xc63c03,0xc03c0380,0x19819819,0x81981981,0x98330600,0x60060060,0x6000600,0x60060060,0xfc662660,0x66066066, 0x66060e0,0x6c660660,0x66066060,0x6060e630,0x1fc1fc1f,0xc1fc1fc1,0xfc3fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, 0xc60c7fe,0x62c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe02c6,0x3c633000,0xc003004, 0x7fe0001,0xf00000c0,0x60c03006,0xc6180,0xc60c060,0x60c00c00,0x7000,0xe060,0x66639c60,0x66006066,0x600606,0x60606001,0x86306006, 0x66636606,0x60060660,0xc0060606,0x61f8696,0xf00600c,0x600300,0x30000000,0x3fc60,0xc60060c7,0xfc06060c,0x60c06003,0x7c00c06, 0x6660c60c,0x60c60c0c,0x1f80c06,0xc1b0666,0xe01b00e,0x3c00600,0x3c43c000,0x3007de00,0x600000,0x40040,0x30000,0x61006607,0xde0c07de, 0x7de00000,0x0,0xf07fefff,0x1f,0x8008c3f7,0xde0e0060,0x6064,0xc01047,0xfe00018c,0xb013f,0x86300061,0xf0911000,0x6000,0x6, 0xc012060,0x3f,0x8063c0cc,0x3cc0c700,0x39c39c39,0xc39c39c1,0x98630600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066, 0x66061f0,0x78660660,0x66066060,0x607fc618,0x3fc3fc3f,0xc3fc3fc3,0xfc7fe600,0x7fc7fc7f,0xc7fc0600,0x60060060,0x60c60c60,0xc60c60c6, 0xc60c7fe,0x64c60c60,0xc60c60c1,0xb060c1b0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0xffe0260,0x6661b000,0xc003000, 0x600000,0xc0,0x60c0300c,0xc7fe0,0xc60c060,0x60c01c00,0x1e07,0xfe078060,0x6663fc60,0x66006066,0x600606,0x60606001,0x86386006, 0x6636606,0x60060660,0xe0060606,0x60f039c,0x1b806018,0x600300,0x30000000,0x70c60,0xc60060c6,0x6060c,0x60c06003,0x7600c06, 0x6660c60c,0x60c60c0c,0x1c0c06,0xc1b03fc,0xe01f01c,0xe00600,0x70000000,0x3007fc00,0x600000,0x40040,0x0,0x62006607,0xfc1807fc, 0x7fc00000,0x0,0xf0000000,0x1,0xc004c307,0xfc1c0060,0x6064,0xc018c0,0x600000d8,0x5f200,0x3180060,0x50a000,0x6000,0x6,0xc012000, 0x0,0xc601c0,0x4201c600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0600,0x60060060,0x6000600,0x60060060,0x60663660,0x66066066,0x66063b8, 0x70660660,0x66066060,0x607f860c,0x70c70c70,0xc70c70c7,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000, 0x68c60c60,0xc60c60c1,0xf060c1f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3300260,0x6661e000,0xc003000,0x600000, 0x180,0x71c03018,0xc7fe0,0xc60c0c0,0x60c01800,0x787,0xfe1e0060,0x6663fc60,0x630060c6,0x600306,0x60606001,0x86186006,0x661e70e, 0x60070c60,0x60060606,0x60f039c,0x19806038,0x600180,0x30000000,0x60c60,0xc60060c6,0x6060c,0x60c06003,0x6700c06,0x6660c60c, 0x60c60c0c,0xc0c06,0xc1b039c,0x1f00e018,0x600600,0x60000000,0x1803f800,0x600000,0x40040,0x39e00,0x63006603,0xf83803f8,0x3f800000, 0x0,0x60000000,0x0,0xc00cc303,0xf8180060,0x6064,0xc01fc0,0x60060070,0x40200,0x18c0060,0x402000,0x6000,0x6,0xc012000,0x0,0x18c0140, 0x2014600,0x3fc3fc3f,0xc3fc3fc3,0xfc7f0300,0x60060060,0x6000600,0x60060060,0x60c61e70,0xe70e70e7,0xe70e71c,0x60e60660,0x66066060, 0x6060060c,0x60c60c60,0xc60c60c6,0xcc60600,0x60060060,0x6000600,0x60060060,0x60c60c60,0xc60c60c6,0xc60c000,0x70c60c60,0xc60c60c0, 0xe060c0e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x33022e0,0x6670c000,0xc003000,0x600600,0x60180,0x31803030, 0x41c0184,0x1831c0c0,0x71c23806,0x6001e0,0x780000,0x62630c60,0xe38261c6,0x600386,0x60606043,0x860c6006,0x661e30c,0x60030c60, 0x740e0607,0xe0f039c,0x31c06030,0x600180,0x30000000,0x61c71,0x830831c3,0x406031c,0x60c06003,0x6300c06,0x6660c318,0x71831c0c, 0x41c0c07,0x1c0e039c,0x1b00e030,0x600600,0x60000000,0x1c41b00e,0x601cc0,0x401f8,0x45240,0xe1803601,0xb03001b0,0x1b000000, 0x0,0x0,0x41,0xc008e711,0xb0300060,0x6034,0x80c02020,0x60060030,0x30c00,0xc60000,0x30c000,0x0,0x7,0x1c012000,0x0,0x3180240, 0x6024608,0x30c30c30,0xc30c30c3,0xc630382,0x60060060,0x6000600,0x60060060,0x61c61e30,0xc30c30c3,0xc30c208,0x70c70e70,0xe70e70e0, 0x6060068c,0x61c61c61,0xc61c61c6,0x1cc62308,0x30430430,0x43040600,0x60060060,0x31860c31,0x83183183,0x18318060,0x31c71c71, 0xc71c71c0,0xe07180e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2203fc0,0x663f6000,0x6006000,0x600600,0x60300, 0x3f81fe7f,0xc7f80187,0xf83f80c0,0x3f83f006,0x600020,0x400060,0x33e6067f,0xc1fe7f87,0xfe6001fe,0x6063fc7f,0x60e7fe6,0x660e3f8, 0x6001f860,0x37fc0603,0xfc06030c,0x30c0607f,0xe06000c0,0x30000000,0x7fc7f,0x83f83fc3,0xfc0603fc,0x60c7fe03,0x61807c6,0x6660c3f8, 0x7f83fc0c,0x7f80fc3,0xfc0e039c,0x3180607f,0xc0600600,0x60000000,0xfc0e00c,0x601986,0x66040040,0x4527f,0xc0803fe0,0xe07fe0e0, 0xe000000,0x0,0x0,0x7f,0x80107ff0,0xe07fc060,0x603f,0x83fe0000,0x60060018,0xf000,0x420000,0xf0000,0x7fe00,0x7,0xfe012000, 0x0,0x2100640,0xc0643f8,0x60660660,0x66066067,0xec3e1fe,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7f860e3f,0x83f83f83,0xf83f8000, 0x5fc3fc3f,0xc3fc3fc0,0x606006fc,0x7fc7fc7f,0xc7fc7fc7,0xfcffe3f8,0x3fc3fc3f,0xc3fc7fe7,0xfe7fe7fe,0x3f860c3f,0x83f83f83, 0xf83f8060,0x7f83fc3f,0xc3fc3fc0,0x607f8060,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6000,0x2201f80,0x3c1e7000,0x6006000, 0x600,0x60300,0xe01fe7f,0xc3f00183,0xe01f0180,0x1f01e006,0x600000,0x60,0x3006067f,0x807c7e07,0xfe6000f8,0x6063fc3e,0x6067fe6, 0x660e0f0,0x6000f060,0x3bf80601,0xf806030c,0x60e0607f,0xe06000c0,0x30000000,0x1ec6f,0xf01ec0,0xf80601ec,0x60c7fe03,0x61c03c6, 0x6660c1f0,0x6f01ec0c,0x3f007c1,0xcc0e030c,0x71c0c07f,0xc0600600,0x60000000,0x7804018,0xe01186,0x66040040,0x39e3f,0x80401fe0, 0x407fe040,0x4000000,0x0,0x0,0x3f,0x203ce0,0x407fc060,0x601f,0x3fe0000,0x60060018,0x0,0x0,0x0,0x7fe00,0x6,0xe6012000,0x0, 0x7e0,0x1807e1f0,0x60660660,0x66066066,0x6c3e07c,0x7fe7fe7f,0xe7fe3fc3,0xfc3fc3fc,0x7e060e0f,0xf00f00,0xf00f0000,0x8f01f81f, 0x81f81f80,0x60600670,0x1ec1ec1e,0xc1ec1ec1,0xec79c0f0,0xf80f80f,0x80f87fe7,0xfe7fe7fe,0x1f060c1f,0x1f01f01,0xf01f0000,0x4f01cc1c, 0xc1cc1cc0,0xc06f00c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x6006000,0x600,0x600,0x0,0x0,0x0,0x0, 0x600000,0x0,0x18000000,0x0,0x0,0x0,0x0,0x0,0x1800,0x0,0x0,0x0,0x600060,0x30000000,0x0,0x0,0xc,0x3,0x0,0x0,0x60000c00,0x0, 0x0,0xc000,0x600600,0x60000000,0x18,0xc03100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f8,0x0,0x0,0x0,0x0,0x6, 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, 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, 0x0,0x1c000000,0x0,0x0,0x0,0x0,0x0,0xc00,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x21c,0x3,0x0,0x0,0x60000c00,0x0,0x0,0xc000, 0x7c0603,0xe0000000,0x10,0xc02300,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x601f0,0x0,0x0,0x0,0x0,0x6,0x12000,0x1000000, 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, 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, 0x0,0x0,0x0,0x0,0x800,0x0,0x0,0x0,0x780000,0xf0000000,0x0,0x0,0x3f8,0x3e,0x0,0x0,0x60000c00,0x0,0x0,0x38000,0x3c0603,0xc0000000, 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, 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, 0x0,0x0,0x0,0x0,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, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 16x32 font const unsigned int font16x32[16*32*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x70000e0,0x3c00730,0xe7001c0,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0x730,0x70000e0,0x3c00730, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x18001c0,0x6600ff0,0xe7003e0,0x0,0x18001c0,0x6600e70,0x18001c0,0x6600e70,0xff0,0x18001c0,0x6600ff0,0xe700000,0x180, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,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, 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, 0xc300ce0,0xe700630,0x0,0x1c00380,0xc300e70,0x1c00380,0xc300e70,0xce0,0x1c00380,0xc300ce0,0xe700000,0x1c0,0x3800c30,0xe700380, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0xc300000,0x0,0xc300000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x700000,0x0,0x0,0x0,0x7c007c00,0x3e000000, 0x0,0x0,0x630,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe000070,0x1800000,0xc60,0x0,0xe000070,0x1800000,0xe000070, 0x1800000,0x0,0xe000070,0x1800000,0x0,0xe00,0x700180,0x70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x3f0,0xfc0,0x0,0x7000000,0x38000000,0x1c0000,0xfc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x7c, 0x1801f00,0x0,0x0,0x1c,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7300000,0x6600000,0x0,0x6600000,0x0,0x0,0x0,0x0,0xe700000, 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, 0xf80,0x70000e0,0x3c00730,0xe700c60,0x0,0x70000e0,0x3c00e70,0x70000e0,0x3c00e70,0xe000730,0x70000e0,0x3c00730,0xe700000,0x700, 0xe003c0,0xe7000e0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300000,0x803c00,0x7c00180, 0xc00300,0x1000000,0x0,0x1c,0x3c007c0,0xfc007e0,0xe01ff8,0x3f03ffc,0x7e007c0,0x0,0x0,0x7c0,0x1c0,0x7f8003f0,0x7f007ff8,0x7ff803f0, 0x70381ffc,0xff0700e,0x7000783c,0x783807c0,0x7fc007c0,0x7fc00fc0,0x7fff7038,0x700ee007,0x780f780f,0x7ffc03f0,0x70000fc0,0x3c00000, 0x3000000,0x38000000,0x1c0000,0x1fc0000,0x380001c0,0xe01c00,0x7f800000,0x0,0x0,0x0,0x0,0x0,0x0,0xfc,0x1801f80,0x0,0x1f80000, 0x7e,0x0,0x0,0x2400000,0xfc00000,0x7ff0000,0x7ffc0000,0x0,0x0,0x0,0x0,0xf30fb0c,0x2400000,0x0,0x240780f,0x1c0,0xfc,0x780f, 0x18003f0,0xe700000,0x7c00000,0x0,0xff0,0x3c00000,0x78007c0,0xc00000,0xff80000,0xf80,0x7c00000,0xc000c00,0x18001c0,0x1c001c0, 0x1c001c0,0x1c003e0,0x7fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007838,0x7c007c0,0x7c007c0,0x7c00000,0x7c67038, 0x70387038,0x7038780f,0x70001fe0,0x30000c0,0x2400f30,0xe700c60,0x0,0x30000c0,0x2400e70,0x30000c0,0x2400e70,0xf700f30,0x30000c0, 0x2400f30,0xe700000,0x300,0xc00240,0xe7000c0,0x38000e70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0, 0x630018c,0x807e00,0xfe00180,0xc00300,0x1000000,0x0,0x38,0xff01fc0,0x3ff01ff0,0x1e01ff8,0x7f83ffc,0x1ff80ff0,0x0,0x0,0xff0, 0x1f003e0,0x7fe00ff8,0x7fc07ff8,0x7ff80ff8,0x70381ffc,0xff0701c,0x7000783c,0x78381ff0,0x7fe01ff0,0x7fe01ff0,0x7fff7038,0x781ee007, 0x3c1e380e,0x7ffc0380,0x380001c0,0x3c00000,0x1800000,0x38000000,0x1c0000,0x3c00000,0x380001c0,0xe01c00,0x3800000,0x0,0x0, 0x0,0x7000000,0x0,0x0,0x1e0,0x18003c0,0x0,0x3fc0000,0x70,0x0,0x0,0x6600000,0x1ff00000,0x1fff0000,0x7ffc0000,0x0,0x0,0x0,0x0, 0xcf0239c,0x3c00000,0x0,0x3c0380e,0x1c0,0x2001fe,0x380e,0x18007f8,0xe700000,0x8600000,0x0,0xff0,0x7e00000,0x8c00870,0x1800000, 0x1ff80000,0x180,0xc600000,0xc000c00,0x38001c0,0x3e003e0,0x3e003e0,0x3e001c0,0x7fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc, 0x7fc07838,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x1fec7038,0x70387038,0x7038380e,0x70003ce0,0x1800180,0x6600cf0,0xe7007c0,0x0, 0x1800180,0x6600e70,0x1800180,0x6600e70,0x7c00cf0,0x1800180,0x6600cf0,0xe700000,0x180,0x1800660,0xe700180,0x38000e70,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630030c,0x3f0e700,0x1e200180,0x1800180,0x21100000,0x0, 0x38,0x1e7819c0,0x38781038,0x1e01c00,0xf080038,0x1c381c38,0x0,0x0,0x1878,0x7fc03e0,0x70e01e18,0x70e07000,0x70001e18,0x703801c0, 0x707038,0x70007c7c,0x7c381c70,0x70701c70,0x70703830,0x1c07038,0x381ce007,0x1c1c3c1e,0x3c0380,0x380001c0,0x7e00000,0xc00000, 0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0,0x70c0000,0xe0, 0x0,0x0,0xc300000,0x38300000,0x3c700000,0x3c0000,0x0,0x0,0x0,0x0,0xce022f4,0x1800000,0x0,0x1803c1e,0x1c0,0x2003c2,0x3c1e, 0x1800e08,0x7e0,0x300000,0x0,0x7e00000,0xe700000,0x600030,0x3000000,0x3f980000,0x180,0x18200000,0xc000c00,0x1e0001c0,0x3e003e0, 0x3e003e0,0x3e003e0,0xfe01e18,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70e07c38,0x1c701c70,0x1c701c70,0x1c700000,0x3c787038, 0x70387038,0x70383c1e,0x70003870,0xc00300,0xc300ce0,0x380,0x0,0xc00300,0xc300000,0xc00300,0xc300000,0xfc00ce0,0xc00300,0xc300ce0, 0x0,0xc0,0x3000c30,0x300,0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630031c,0xff8c300, 0x1c000180,0x1800180,0x39380000,0x0,0x70,0x1c3801c0,0x203c001c,0x3e01c00,0x1c000038,0x381c3838,0x0,0x0,0x1038,0xe0e03e0,0x70703c08, 0x70707000,0x70003808,0x703801c0,0x707070,0x70007c7c,0x7c383838,0x70383838,0x70387010,0x1c07038,0x381c700e,0x1e3c1c1c,0x780380, 0x1c0001c0,0xe700000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0, 0x0,0xe000000,0xe0,0x0,0x1000100,0x3800,0x70100000,0x38700000,0x780000,0x1c0,0x7801ce0,0xe380000,0x0,0x2264,0x0,0x0,0x1c1c, 0x0,0x200780,0x1c1c,0x1800c00,0x1818,0x7f00000,0x0,0x18180000,0xc300000,0x600070,0x0,0x7f980000,0x180,0x18300000,0xc000c00, 0x3000000,0x3e003e0,0x3e003e0,0x3e003e0,0xee03c08,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838, 0x38380000,0x38387038,0x70387038,0x70381c1c,0x7fc03870,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xbc00000,0x0,0x0,0x0,0x0,0x0,0x0, 0x38000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0xe88c300,0x1c000180,0x38001c0, 0xfe00180,0x0,0x70,0x1c3801c0,0x1c001c,0x6e01c00,0x1c000078,0x381c3818,0x0,0x40000,0x40000038,0x1c0607e0,0x70703800,0x70707000, 0x70003800,0x703801c0,0x7070e0,0x70007c7c,0x7c383838,0x70383838,0x70387000,0x1c07038,0x381c700e,0xf780e38,0x700380,0x1c0001c0, 0x1c380000,0x0,0x38000000,0x1c0000,0x3800000,0x38000000,0x1c00,0x3800000,0x0,0x0,0x0,0x7000000,0x0,0x0,0x1c0,0x18001c0,0x0, 0xe000000,0xe0,0x0,0x1000100,0x4400,0x70000000,0x38700000,0x700000,0xe0,0x7001c70,0xe380000,0x0,0x2264,0x0,0x0,0xe38,0x0, 0x200700,0xe38,0x1800c00,0x300c,0xc300000,0x0,0x300c0000,0xc300180,0x6003c0,0x0,0x7f980000,0x180,0x18300000,0xc000c00,0x1800000, 0x7e007e0,0x7e007e0,0x7e003e0,0xee03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70707c38,0x38383838,0x38383838,0x38380000, 0x38387038,0x70387038,0x70380e38,0x7ff039f0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e00000,0x0,0x0,0x0,0x40000,0x0,0x0,0x38000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6300318,0x1c80e700,0x1c000180,0x38001c0,0x3800180, 0x0,0xe0,0x381c01c0,0x1c001c,0x6e01c00,0x38000070,0x381c381c,0x0,0x3c0000,0x78000078,0x38030770,0x70707800,0x70387000,0x70007000, 0x703801c0,0x7071c0,0x7000745c,0x7638701c,0x7038701c,0x70387000,0x1c07038,0x1c38718e,0x7700f78,0xf00380,0xe0001c0,0x381c0000, 0x7e0,0x39e003e0,0x79c03f0,0x3ffc079c,0x39e01fc0,0xfe01c1e,0x3807778,0x39e007e0,0x39e0079c,0x73c07e0,0x7ff83838,0x701ce007, 0x783c701c,0x1ffc01c0,0x18001c0,0x0,0x1c000100,0xe0,0x0,0x1000100,0x4200,0x70000000,0x70700100,0xf00100,0x10000e0,0x7000c70, 0xc700000,0x0,0x2204,0x7e00000,0x1e380100,0x1ffc0f78,0x0,0xf80700,0xf78,0x1800e00,0x63e6,0x18300000,0x0,0x6fe60000,0xe700180, 0xc00060,0x3838,0x7f980000,0x180,0x18300000,0xc000c00,0x18001c0,0x7700770,0x7700770,0x77007f0,0xee07800,0x70007000,0x70007000, 0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1008,0x707c7038,0x70387038,0x70380f78,0x707039c0,0x7e007e0,0x7e007e0, 0x7e007e0,0x1f3c03e0,0x3f003f0,0x3f003f0,0x1fc01fc0,0x1fc01fc0,0x7f039e0,0x7e007e0,0x7e007e0,0x7e00380,0x7ce3838,0x38383838, 0x3838701c,0x39e0701c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x6307fff,0x1c807e0c,0xe000180, 0x30000c0,0x3800180,0x0,0xe0,0x381c01c0,0x1c001c,0xce01fe0,0x38000070,0x381c381c,0x3800380,0xfc0000,0x7e0000f0,0x30030770, 0x70707000,0x70387000,0x70007000,0x703801c0,0x707380,0x700076dc,0x7638701c,0x7038701c,0x70387800,0x1c07038,0x1c3873ce,0x7f00770, 0xe00380,0xe0001c0,0x700e0000,0x1ff8,0x3ff00ff0,0xffc0ff8,0x3ffc0ffc,0x3bf01fc0,0xfe01c3c,0x3807f78,0x3bf00ff0,0x3ff00ffc, 0x77e0ff0,0x7ff83838,0x3838e007,0x3c783838,0x1ffc01c0,0x18001c0,0x0,0x7ff00380,0x1e0,0x0,0x1000100,0x4200,0x78000000,0x70700380, 0xe00380,0x3800060,0xe000e30,0x1c600000,0x0,0x2204,0xff00000,0x7f7c0380,0x1ffc0770,0x1c0,0x3fc0700,0x18040770,0x1800780,0x4e12, 0x18300104,0x0,0x4c320000,0x7e00180,0x1c00030,0x3838,0x7f980000,0x180,0x18302080,0xc000c00,0x18001c0,0x7700770,0x7700770, 0x7700770,0x1ee07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c381c,0x705c7038,0x70387038, 0x70380770,0x70383b80,0x1ff81ff8,0x1ff81ff8,0x1ff81ff8,0x3fbe0ff0,0xff80ff8,0xff80ff8,0x1fc01fc0,0x1fc01fc0,0xff83bf0,0xff00ff0, 0xff00ff0,0xff00380,0xffc3838,0x38383838,0x38383838,0x3ff03838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x1c0,0x7fff,0x1c803c38,0xf000000,0x70000e0,0xfe00180,0x0,0x1c0,0x381c01c0,0x3c0078,0xce01ff0,0x39e000f0,0x1c38381c,0x3800380, 0x3e07ffc,0xf8001f0,0x307b0770,0x70e07000,0x70387000,0x70007000,0x703801c0,0x707700,0x700076dc,0x7638701c,0x7038701c,0x70387e00, 0x1c07038,0x1c3873ce,0x3e007f0,0x1e00380,0x70001c0,0x0,0x1038,0x3c381e18,0x1c7c1e3c,0x3801e3c,0x3c7801c0,0xe01c78,0x380739c, 0x3c781c38,0x3c381c3c,0x7c21e10,0x7003838,0x3838700e,0x1ef03838,0x3c01c0,0x18001c0,0x0,0x7fe007c0,0x1c0,0x0,0x1000100,0x6400, 0x7e000000,0x707007c0,0x1e007c0,0x7c00070,0xe000638,0x18600000,0x0,0x0,0x1e100000,0x73ce07c0,0x3c07f0,0x1c0,0x7240700,0x1ddc3ffe, 0x1800de0,0x8c01,0x1870030c,0x0,0x8c310000,0x3c00180,0x3800030,0x3838,0x7f980000,0x180,0x183030c0,0xc000c00,0x430001c0,0x7700770, 0x7700770,0x7700770,0x1ce07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x70387638,0x701c701c,0x701c701c,0x701c1c38,0x70dc7038, 0x70387038,0x703807f0,0x70383b80,0x10381038,0x10381038,0x10381038,0x21e71e18,0x1e3c1e3c,0x1e3c1e3c,0x1c001c0,0x1c001c0,0x1e383c78, 0x1c381c38,0x1c381c38,0x1c380380,0x1c383838,0x38383838,0x38383838,0x3c383838,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0x1e8000e0,0x1f000000,0x70000e0,0x39380180,0x0,0x1c0,0x3b9c01c0,0x3c07f0,0x18e01078,0x3bf800e0, 0x7e0383c,0x3800380,0x1f807ffc,0x3f001c0,0x61ff0e38,0x7fc07000,0x70387ff0,0x7ff07000,0x7ff801c0,0x707f00,0x7000729c,0x7338701c, 0x7070701c,0x70703fc0,0x1c07038,0x1e7873ce,0x1c003e0,0x3c00380,0x70001c0,0x0,0x1c,0x3c381c00,0x1c3c1c1c,0x3801c3c,0x383801c0, 0xe01cf0,0x380739c,0x38381c38,0x3c381c3c,0x7801c00,0x7003838,0x3838700e,0xfe03c78,0x7801c0,0x18001c0,0x0,0x1c000c20,0xff8, 0x0,0x1ff01ff0,0x3818,0x3fc00100,0x707e0c20,0x3c00c20,0xc200030,0xc000618,0x18c00000,0x0,0x0,0x1c000080,0xe1ce0c20,0x7803e0, 0x1c0,0xe200700,0xff83ffe,0x1801878,0x9801,0x1cf0071c,0x7ffc0000,0x8c310000,0x7ffe,0x7000030,0x3838,0x3f980380,0x180,0xc6038e0, 0x7f9c7f9c,0x3e1c01c0,0xe380e38,0xe380e38,0xe380f78,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0,0x1c001c0,0xfe387338,0x701c701c, 0x701c701c,0x701c0e70,0x719c7038,0x70387038,0x703803e0,0x70383b80,0x1c001c,0x1c001c,0x1c001c,0xe71c00,0x1c1c1c1c,0x1c1c1c1c, 0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380000,0x3c383838,0x38383838,0x38383c78,0x3c383c78,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x630,0xf800380,0x3f830000,0x70000e0,0x31080180,0x0,0x380,0x3b9c01c0, 0x7807e0,0x38e00038,0x3c3800e0,0xff01c3c,0x3800380,0x7c000000,0x7c03c0,0x61870e38,0x7fc07000,0x70387ff0,0x7ff070fc,0x7ff801c0, 0x707f80,0x7000739c,0x7338701c,0x7ff0701c,0x7fe00ff0,0x1c07038,0xe7073ce,0x1c003e0,0x3800380,0x38001c0,0x0,0x1c,0x381c3800, 0x381c380e,0x380381c,0x383801c0,0xe01de0,0x380739c,0x3838381c,0x381c381c,0x7001e00,0x7003838,0x1c70718e,0x7e01c70,0xf00380, 0x18001e0,0x1e000000,0x1c001bb0,0xff8,0x0,0x1000100,0xe0,0xff00300,0x707e1bb0,0x3801bb0,0x1bb00010,0x8000308,0x30c00000,0x0, 0x0,0x1e0000c0,0xe1ce1bb0,0xf003e0,0x1c0,0x1c203ff8,0x63003e0,0x180181c,0x9801,0xfb00e38,0x7ffc0000,0x8fc10000,0x7ffe,0xe000860, 0x3838,0x1f980380,0x180,0x7c01c70,0x1f001f0,0x1f003c0,0xe380e38,0xe380e38,0xe380e38,0x1cfc7000,0x7ff07ff0,0x7ff07ff0,0x1c001c0, 0x1c001c0,0xfe387338,0x701c701c,0x701c701c,0x701c07e0,0x731c7038,0x70387038,0x703803e0,0x70383980,0x1c001c,0x1c001c,0x1c001c, 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x387c3838,0x38383838,0x38381c70, 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc30,0x7f00e00,0x33c30000,0x70000e0,0x1007ffe, 0x0,0x380,0x3b9c01c0,0xf00078,0x30e0001c,0x3c1c01c0,0x1c381fdc,0x0,0x70000000,0x1c0380,0x63030e38,0x70707000,0x70387000,0x700070fc, 0x703801c0,0x707b80,0x7000739c,0x7338701c,0x7fc0701c,0x7fc001f0,0x1c07038,0xe703e5c,0x3e001c0,0x7800380,0x38001c0,0x0,0x7fc, 0x381c3800,0x381c380e,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7001fc0,0x7003838,0x1c70718e,0x7c01c70, 0xe01f00,0x180007c,0x7f8c0000,0x7fc03fb8,0x1c0,0x0,0x1000100,0x700,0x1f00600,0x70703fb8,0x7803fb8,0x3fb80000,0x8000000,0x180, 0x0,0x0,0x1fc00060,0xe1ce3fb8,0xe001c0,0x1c0,0x1c203ff8,0xc1801c0,0x180c,0x9801,0x1c70,0xc0000,0x8cc10000,0x180,0xfe007c0, 0x3838,0x7980380,0xff0,0xe38,0x3e003e00,0x3e000380,0xe380e38,0xe380e38,0xe380e38,0x38e07000,0x70007000,0x70007000,0x1c001c0, 0x1c001c0,0x70387338,0x701c701c,0x701c701c,0x701c03c0,0x731c7038,0x70387038,0x703801c0,0x703838e0,0x7fc07fc,0x7fc07fc,0x7fc07fc, 0xe73800,0x380e380e,0x380e380e,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x38dc3838,0x38383838,0x38381c70, 0x381c1c70,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xc60,0xf83878,0x71e30000,0x70000e0,0x1007ffe, 0x7f0,0x380,0x381c01c0,0x1e0003c,0x60e0001c,0x381c01c0,0x381c079c,0x0,0x7c000000,0x7c0380,0x63031c1c,0x70307000,0x70387000, 0x7000701c,0x703801c0,0x7071c0,0x7000739c,0x71b8701c,0x7000701c,0x71e00078,0x1c07038,0xe703e7c,0x7e001c0,0xf000380,0x38001c0, 0x0,0x1ffc,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fc0,0x380739c,0x3838381c,0x381c381c,0x7000ff0,0x7003838,0x1ef03bdc, 0x3800ee0,0x1e01f00,0x180007c,0x61fc0000,0x7fc07f3c,0x1c0,0x0,0x1000100,0x1800,0x780c00,0x70707f3c,0xf007f3c,0x7f3c0000,0x0, 0x3c0,0x3ffcffff,0x0,0xff00030,0xe1fe7f3c,0x1e001c0,0x1c0,0x1c200700,0xc183ffe,0xe0c,0x9801,0x1ff038e0,0xc07f0,0x8c610000, 0x180,0x0,0x3838,0x1980380,0x0,0x1ff0071c,0xe000e000,0xe0000f80,0x1c1c1c1c,0x1c1c1c1c,0x1c1c1e38,0x38e07000,0x70007000,0x70007000, 0x1c001c0,0x1c001c0,0x703871b8,0x701c701c,0x701c701c,0x701c03c0,0x761c7038,0x70387038,0x703801c0,0x70703870,0x1ffc1ffc,0x1ffc1ffc, 0x1ffc1ffc,0xfff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c7ffc,0x389c3838,0x38383838, 0x38380ee0,0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0xfffc,0xbc60fc,0x70e30000,0x70000e0, 0x180,0x7f0,0x700,0x381c01c0,0x3e0001c,0x7ffc001c,0x381c03c0,0x381c001c,0x0,0x1f807ffc,0x3f00380,0x63031ffc,0x70387000,0x70387000, 0x7000701c,0x703801c0,0x7071e0,0x7000701c,0x71b8701c,0x7000701c,0x70f00038,0x1c07038,0x7e03e7c,0x77001c0,0xe000380,0x1c001c0, 0x0,0x3c1c,0x381c3800,0x381c3ffe,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x70003f8,0x7003838,0xee03bdc, 0x3c00ee0,0x3c00380,0x18000e0,0xf00000,0x1c007e7c,0x3c0,0x0,0x1000100,0x0,0x381800,0x70707e7c,0xe007e7c,0x7e7c0000,0x0,0x7c0, 0x0,0x0,0x3f80018,0xe1fe7e7c,0x3c001c0,0x1c0,0x1c200700,0xc183ffe,0xf0c,0x8c01,0x38e0,0xc07f0,0x8c710000,0x180,0x0,0x3838, 0x1980000,0x0,0x71c,0x7000f0,0x700f00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x3fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 0x703871b8,0x701c701c,0x701c701c,0x701c07e0,0x7c1c7038,0x70387038,0x703801c0,0x7ff03838,0x3c1c3c1c,0x3c1c3c1c,0x3c1c3c1c, 0x3fff3800,0x3ffe3ffe,0x3ffe3ffe,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x391c3838,0x38383838,0x38380ee0, 0x381c0ee0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfffc,0x9c01ce,0x70f60000,0x70000e0,0x180, 0x0,0x700,0x381c01c0,0x780001c,0x7ffc001c,0x381c0380,0x381c003c,0x0,0x3e07ffc,0xf800380,0x63031ffc,0x70387000,0x70387000, 0x7000701c,0x703801c0,0x7070f0,0x7000701c,0x71b8701c,0x7000701c,0x70700038,0x1c07038,0x7e03e7c,0xf7801c0,0x1e000380,0x1c001c0, 0x0,0x381c,0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01fe0,0x380739c,0x3838381c,0x381c381c,0x7000078,0x7003838,0xee03a5c, 0x7c00fe0,0x78001c0,0x18001c0,0x0,0x1c003ef8,0x380,0x0,0x1000100,0x810,0x383000,0x70703ef8,0x1e003ef8,0x3ef80000,0x0,0x7c0, 0x0,0x0,0x78000c,0xe1c03ef8,0x78001c0,0x1c0,0x1c200700,0x63001c0,0x18003f8,0x4e12,0x1c70,0xc0000,0x4c320000,0x180,0x0,0x3838, 0x1980000,0x0,0xe38,0x700118,0x701e00,0x1ffc1ffc,0x1ffc1ffc,0x1ffc1ffc,0x7fe07000,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 0x703871b8,0x701c701c,0x701c701c,0x701c0e70,0x7c1c7038,0x70387038,0x703801c0,0x7fc0381c,0x381c381c,0x381c381c,0x381c381c, 0x78e03800,0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0000,0x3b1c3838,0x38383838,0x38380fe0, 0x381c0fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1860,0x9c0186,0x707e0000,0x30000c0,0x180, 0x0,0xe00,0x183801c0,0xf00001c,0xe0001c,0x181c0380,0x381c0038,0x0,0xfc0000,0x7e000000,0x61873c1e,0x70383800,0x70707000,0x7000381c, 0x703801c0,0x707070,0x7000701c,0x70f83838,0x70003838,0x70780038,0x1c07038,0x7e03c3c,0xe3801c0,0x1c000380,0xe001c0,0x0,0x381c, 0x381c3800,0x381c3800,0x380381c,0x383801c0,0xe01ef0,0x380739c,0x3838381c,0x381c381c,0x7000038,0x7003838,0xfe03e7c,0xfe007c0, 0x70001c0,0x18001c0,0x0,0xe001ff0,0x380,0x0,0x1000100,0x162c,0x381800,0x30701ff0,0x1c001ff0,0x1ff00000,0x0,0x3c0,0x0,0x0, 0x380018,0xe1c01ff0,0x70001c0,0x1c0,0x1c200700,0xff801c0,0x18000f0,0x63e6,0xe38,0x0,0x6c3e0000,0x0,0x0,0x3838,0x1980000,0x0, 0x1c70,0xf0000c,0xf01c00,0x3c1e3c1e,0x3c1e3c1e,0x3c1e3c1c,0x70e03800,0x70007000,0x70007000,0x1c001c0,0x1c001c0,0x707070f8, 0x38383838,0x38383838,0x38381c38,0x38387038,0x70387038,0x703801c0,0x7000381c,0x381c381c,0x381c381c,0x381c381c,0x70e03800, 0x38003800,0x38003800,0x1c001c0,0x1c001c0,0x381c3838,0x381c381c,0x381c381c,0x381c0380,0x3e1c3838,0x38383838,0x383807c0,0x381c07c0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x18c0,0x9c0186,0x783c0000,0x38001c0,0x180,0x3800000, 0x3800e00,0x1c3801c0,0x1e00003c,0xe00038,0x1c1c0780,0x381c0038,0x3800380,0x3c0000,0x78000000,0x61ff380e,0x70383808,0x70707000, 0x7000381c,0x703801c0,0x40707078,0x7000701c,0x70f83838,0x70003838,0x70384038,0x1c07038,0x7e03c3c,0x1e3c01c0,0x3c000380,0xe001c0, 0x0,0x383c,0x3c381c00,0x1c3c1c00,0x3801c3c,0x383801c0,0xe01c78,0x380739c,0x38381c38,0x3c381c3c,0x7000038,0x7003878,0x7c01e78, 0x1ef007c0,0xf0001c0,0x18001c0,0x0,0xe000ee0,0x7800380,0xe380000,0x1001ff0,0x2242,0x40380c00,0x38700ee0,0x3c000ee0,0xee00000, 0x0,0x0,0x0,0x0,0x380030,0xe1c00ee0,0xf0001c0,0x1c0,0xe200700,0xdd801c0,0x1800038,0x300c,0x71c,0x0,0x300c0000,0x0,0x0,0x3838, 0x1980000,0x0,0x38e0,0xb0000c,0xb01c08,0x380e380e,0x380e380e,0x380e380e,0x70e03808,0x70007000,0x70007000,0x1c001c0,0x1c001c0, 0x707070f8,0x38383838,0x38383838,0x3838381c,0x38387038,0x70387038,0x703801c0,0x7000381c,0x383c383c,0x383c383c,0x383c383c, 0x70e01c00,0x1c001c00,0x1c001c00,0x1c001c0,0x1c001c0,0x1c383838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383878,0x38783878,0x387807c0, 0x3c3807c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x18c0,0x10b801ce,0x3c3e0000,0x38001c0,0x180, 0x3800000,0x3801c00,0x1e7801c0,0x3c002078,0xe02078,0x1c380700,0x1c3810f0,0x3800380,0x40000,0x40000380,0x307b380e,0x70701e18, 0x70e07000,0x70001c1c,0x703801c0,0x60e0703c,0x7000701c,0x70f83c78,0x70003c70,0x703c70f0,0x1c03870,0x3c01c3c,0x3c1c01c0,0x78000380, 0x7001c0,0x0,0x3c7c,0x3c381e18,0x1c7c1e0c,0x3801c3c,0x383801c0,0xe01c38,0x3c0739c,0x38381c38,0x3c381c3c,0x7001078,0x7803c78, 0x7c01c38,0x1c780380,0x1e0001c0,0x18001c0,0x0,0x70c06c0,0x7000380,0xe300000,0x1000100,0x2142,0x70f00600,0x3c7006c0,0x780006c0, 0x6c00000,0x0,0x0,0x0,0x0,0x10780060,0x73e206c0,0x1e0001c0,0x1c0,0x7240700,0x180c01c0,0x1800018,0x1818,0x30c,0x0,0x18180000, 0x0,0x0,0x3c78,0x1980000,0x0,0x30c0,0x130000c,0x1301c18,0x380e380e,0x380e380e,0x380e380e,0x70e01e18,0x70007000,0x70007000, 0x1c001c0,0x1c001c0,0x70e070f8,0x3c783c78,0x3c783c78,0x3c781008,0x7c783870,0x38703870,0x387001c0,0x70003a3c,0x3c7c3c7c,0x3c7c3c7c, 0x3c7c3c7c,0x79f11e18,0x1e0c1e0c,0x1e0c1e0c,0x1c001c0,0x1c001c0,0x1c783838,0x1c381c38,0x1c381c38,0x1c380380,0x1c383c78,0x3c783c78, 0x3c780380,0x3c380380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x38c0,0x1ff800fc,0x1fee0000, 0x1800180,0x180,0x3800000,0x3801c00,0xff01ffc,0x3ffc3ff0,0xe03ff0,0xff00700,0x1ff81fe0,0x3800380,0x0,0x380,0x3000780f,0x7ff00ff8, 0x7fc07ff8,0x70000ffc,0x70381ffc,0x7fe0701c,0x7ff8701c,0x70781ff0,0x70001ff0,0x701c7ff0,0x1c01fe0,0x3c01c38,0x380e01c0,0x7ffc0380, 0x7001c0,0x0,0x1fdc,0x3ff00ff0,0xffc0ffc,0x3800fdc,0x38383ffe,0xe01c3c,0x1fc739c,0x38380ff0,0x3ff00ffc,0x7001ff0,0x3f81fb8, 0x7c01c38,0x3c3c0380,0x1ffc01c0,0x18001c0,0x0,0x3fc0380,0x7000380,0xc70718c,0x1000100,0x2244,0x7ff00200,0x1fff0380,0x7ffc0380, 0x3800000,0x0,0x0,0x0,0x0,0x1ff000c0,0x7f7e0380,0x1ffc01c0,0x1c0,0x3fc3ffe,0x1c0,0x1800018,0x7e0,0x104,0x0,0x7e00000,0x7ffe, 0x0,0x3fde,0x1980000,0x0,0x2080,0x3300018,0x3300ff0,0x780f780f,0x780f780f,0x780f780e,0xf0fe0ff8,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc, 0x1ffc1ffc,0x7fc07078,0x1ff01ff0,0x1ff01ff0,0x1ff00000,0x7ff01fe0,0x1fe01fe0,0x1fe001c0,0x70003bf8,0x1fdc1fdc,0x1fdc1fdc, 0x1fdc1fdc,0x3fbf0ff0,0xffc0ffc,0xffc0ffc,0x3ffe3ffe,0x3ffe3ffe,0xff03838,0xff00ff0,0xff00ff0,0xff00000,0x3ff01fb8,0x1fb81fb8, 0x1fb80380,0x3ff00380,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0,0x31c0,0x7e00078,0x7cf0000,0x1800180, 0x0,0x3800000,0x3803800,0x3c01ffc,0x3ffc0fe0,0xe01fc0,0x3e00e00,0x7e00f80,0x3800380,0x0,0x380,0x18007007,0x7fc003f0,0x7f007ff8, 0x700003f0,0x70381ffc,0x3f80701e,0x7ff8701c,0x707807c0,0x700007c0,0x701e1fc0,0x1c00fc0,0x3c01818,0x780f01c0,0x7ffc0380,0x3801c0, 0x0,0xf9c,0x39e003e0,0x79c03f0,0x380079c,0x38383ffe,0xe01c1e,0x7c739c,0x383807e0,0x39e0079c,0x7000fc0,0x1f80f38,0x3801c38, 0x781e0380,0x1ffc01c0,0x18001c0,0x0,0x1f80100,0xe000700,0x1c60718c,0x1000100,0x1e3c,0x1fc00100,0x7ff0100,0x7ffc0100,0x1000000, 0x0,0x0,0x0,0x0,0xfc00080,0x3e3c0100,0x1ffc01c0,0x1c0,0xf83ffe,0x1c0,0x1800838,0x0,0x0,0x0,0x0,0x7ffe,0x0,0x3b9e,0x1980000, 0x0,0x0,0x2300038,0x23003e0,0x70077007,0x70077007,0x70077007,0xe0fe03f0,0x7ff87ff8,0x7ff87ff8,0x1ffc1ffc,0x1ffc1ffc,0x7f007078, 0x7c007c0,0x7c007c0,0x7c00000,0xc7c00fc0,0xfc00fc0,0xfc001c0,0x700039f0,0xf9c0f9c,0xf9c0f9c,0xf9c0f9c,0x1f1e03e0,0x3f003f0, 0x3f003f0,0x3ffe3ffe,0x3ffe3ffe,0x7e03838,0x7e007e0,0x7e007e0,0x7e00000,0x63e00f38,0xf380f38,0xf380380,0x39e00380,0x0,0x0, 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, 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, 0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1c0,0x18001c0,0x0,0x0,0xe000700,0x18600000,0x1000100,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800ff0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0x1800000,0x0,0x6300070,0x6300000,0x0, 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, 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, 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, 0x0,0x0,0x1c,0x0,0xe00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x700,0x1e0,0x18003c0,0x0,0x0,0xc000700,0x18c00000,0x1000000,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x18007e0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x1980000,0xc00000, 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, 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, 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, 0x3f0,0xfc0,0x0,0x0,0x0,0x0,0x838,0x0,0x1e00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0xf00,0xfc,0x1801f80,0x0,0x0,0x8008e00,0x30c00000, 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, 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, 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, 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, 0x0,0x0,0xff0,0x0,0x1fc00000,0x0,0x0,0x3800001c,0x0,0x0,0x0,0x3e00,0x7c,0x1801f00,0x0,0x0,0x800fe00,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200000,0x0,0x1800000,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x7c00000,0x0,0x3001fc,0x300000, 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, 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, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1800000,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 19x38 font const unsigned int font19x38[19*38*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x1e00000,0x3,0x80000700,0x3c00000,0x380000,0x70003c00,0x0,0xe1800e,0x1c00,0xf000e18,0x0,0x0,0x700000e0,0x780000,0x7000,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c0000e,0x7e003,0xe60071c0,0x7f80000,0x1,0xc0000e00,0x7e0038e,0x1c0000, 0xe0007e00,0x38e00000,0xf98007,0x3800,0x1f800f98,0x1c70000,0x0,0x380001c0,0xfc0071,0xc000e000,0x0,0x0,0x0,0x0,0x3e00000,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0001c,0xe7006,0x7c0071c0,0xe180000,0x0,0xe0001c00,0xe70038e,0xe0001,0xc000e700,0x38e00000, 0x19f0003,0x80007000,0x39c019f0,0x1c70000,0x0,0x1c000380,0x1ce0071,0xc001c000,0x0,0x0,0x0,0x0,0x7f00000,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,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, 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, 0x0,0x0,0x700038,0x1c3806,0x3c0071c0,0xc0c0000,0x0,0x70003800,0x1c38038e,0x70003,0x8001c380,0x38e00000,0x18f0001,0xc000e000, 0x70e018f0,0x1c70000,0x0,0xe000700,0x3870071,0xc0038000,0x0,0x0,0x0,0x0,0xe380000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 0xe,0x380,0x1800000,0xe00000,0x38001800,0x0,0x38,0xe00,0x6000000,0x0,0x1,0xc0000070,0x300000,0x3800,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 0x0,0x0,0xc3000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800000,0x0,0x0,0x0,0xe0,0x1c000f,0xc0000000,0x0,0x0, 0x0,0xc0c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7000007,0x3c003,0xc6000000,0xc180000,0x7,0x700, 0x3c00000,0x700000,0x70003c00,0x0,0xf1801c,0x1c00,0xf000f18,0x0,0x0,0xe00000e0,0x780000,0x7000,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x7,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf800e,0x3e0000,0x0,0x0,0x0,0x1e00000,0x0,0x1, 0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7cc00,0x660,0x0,0x0,0x66000000,0x0,0x0,0x0,0x0,0x7,0x1c000000,0x0,0x0,0x0,0x3fe00000, 0x0,0x0,0x7000000,0x0,0x0,0x0,0x3e0,0x7c001f,0xe0000000,0x0,0x0,0x0,0xe1c0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x1f80,0x380000e,0x7e007,0xe60071c0,0xc180000,0x3,0x80000e00,0x7e0038e,0x380000,0xe0007e00,0x38e00f00,0x1f9800e, 0x3800,0x1f801f98,0x1c70000,0x0,0x700001c0,0xfc0071,0xc000e007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0x61c00600,0x1e00007e,0x70000,0x18003000,0x1800000,0x0,0x0,0x1c01f0,0x7e003f,0xc003f800, 0x1e03ffc,0x7f01ff,0xfc03f000,0x7e000000,0x0,0x0,0xfc0,0x1e,0x7fe000,0x7e03fe00,0x3fff07ff,0xe007e038,0x383ffe0,0xff81c01, 0xe1c000f8,0xf8f00e0,0xfc01ffc,0x3f00ff,0xc000fe07,0xfffc7007,0x1c007700,0x73c01ef,0x78ffff,0xfe0380,0xfe000,0x38000000,0x1800000, 0x700000,0x38,0x1f,0xe000001c,0x1c00,0x1c00700,0x7fc0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0xfc0000, 0x0,0x7f00000,0x0,0x1,0x98000000,0x7f00000,0x3ffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0xcf81f,0xee3807e0,0x0,0x0,0x7e03c01e,0x1c, 0x0,0x1f800000,0xf0078038,0xfc007,0x1c000000,0xfe00000,0x0,0x0,0x3fe000f0,0xf,0xc001f800,0x6000000,0xffc000,0x0,0x1c0007e0, 0x360,0x6c0010,0x70000700,0xf0001e,0x3c000,0x78000f00,0x7f800ff,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0, 0x7807007,0xe000fc00,0x1f8003f0,0x7e0000,0x1f867,0x70e00e,0x1c01c380,0x38f00787,0x3fe0,0x180000c,0x66006,0x7c0071c0,0xe380000, 0x1,0x80000c00,0x660038e,0x180000,0xc0006600,0x38e0078e,0x19f0006,0x3000,0x198019f0,0x1c70000,0x0,0x30000180,0xcc0071,0xc000c007, 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, 0x38003800,0x1800000,0x0,0x0,0x3807fc,0x1fe00ff,0xf00ffe00,0x3e03ffc,0xff81ff,0xfc07fc01,0xff800000,0x0,0x0,0x3fe0,0xfe001e, 0x7ff801,0xff83ff80,0x3fff07ff,0xe01ff838,0x383ffe0,0xff81c03,0xc1c000f8,0xf8f80e0,0x3ff01fff,0xffc0ff,0xf003ff87,0xfffc7007, 0x1e00f700,0x71c03c7,0x70ffff,0xfe01c0,0xfe000,0x7c000000,0xc00000,0x700000,0x38,0x3f,0xe000001c,0x1c00,0x1c00700,0x7fc0000, 0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x3f800e,0x3f8000,0x0,0x3fe0000,0x0,0xff00000,0x0,0x3,0xc000000,0x1ffc0000,0xfffe00, 0xffff0,0x0,0x0,0x0,0x0,0x0,0xc781f,0xee3803c0,0x0,0x0,0x3c01c01c,0x1c,0xc000,0x7fc00000,0x70070038,0x3fe007,0x1c000000,0x1ff80000, 0x0,0x0,0x3fe003fc,0x1f,0xe003fc00,0xc000000,0x3ffc000,0x0,0x7c000ff0,0x60,0xc0000,0x30000700,0xf0001e,0x3c000,0x78000f00, 0x3f000ff,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x7c0701f,0xf803ff00,0x7fe00ffc,0x1ff8000,0x7fe67, 0x70e00e,0x1c01c380,0x38700707,0x7ff0,0xc00018,0xc3006,0x3c0071c0,0x7f00000,0x0,0xc0001800,0xc30038e,0xc0001,0x8000c300,0x38e003fc, 0x18f0003,0x6000,0x30c018f0,0x1c70000,0x0,0x18000300,0x1860071,0xc0018007,0x38e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe1801fc0,0x618001ff,0x70000,0x30001800,0x21840000,0x0,0x0,0x380ffe,0x1fe00ff, 0xfc0fff00,0x3e03ffc,0x1ff81ff,0xfc0ffe03,0xffc00000,0x0,0x0,0x7ff0,0x3ff803f,0x7ffc03,0xffc3ffc0,0x3fff07ff,0xe03ffc38,0x383ffe0, 0xff81c07,0x81c000f8,0xf8f80e0,0x7ff81fff,0x81ffe0ff,0xf80fff87,0xfffc7007,0xe00e700,0x70e0387,0x80f0ffff,0xe001c0,0xe000, 0xfe000000,0xe00000,0x700000,0x38,0x3c,0x1c,0x1c00,0x1c00700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x78000e,0x3c000, 0x0,0x7ff0000,0x0,0xf100000,0x0,0x7,0xe000000,0x7ffc0000,0x1fffe00,0xffff0,0x0,0x0,0x0,0x0,0x0,0x3,0xf780180,0x0,0x0,0x1801e03c, 0x1c,0xc000,0xffc00000,0x780f0038,0x786000,0x7f00,0x18380000,0x0,0xfe00,0x30c,0x10,0x70020e00,0x1c000000,0x7f8c000,0x0,0x6c001c38, 0x60,0xc0000,0x70000700,0x1f8003f,0x7e000,0xfc001f80,0x3f000ff,0xf03ffc1f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc, 0x7c0703f,0xfc07ff80,0xfff01ffe,0x3ffc000,0xffec7,0x70e00e,0x1c01c380,0x38780f07,0xf070,0xe00038,0x1c3800,0x0,0x3e00000,0x0, 0xe0003800,0x1c380000,0xe0003,0x8001c380,0x3e0,0x3,0x8000e000,0x70e00000,0x0,0x0,0x1c000700,0x3870000,0x38007,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xe3807ff0,0xc0c003c1,0x70000,0x70001c00, 0x718e0000,0x0,0x0,0x700f1e,0x1ce00c0,0x3c0c0f80,0x7e03800,0x3e08000,0x381e0f03,0xc1e00000,0x0,0x0,0x7078,0x783c03f,0x701e07, 0xc1c383e0,0x38000700,0x7c1c38,0x3801c00,0x381c0f,0x1c000fc,0x1f8f80e0,0x78781c07,0x81e1e0e0,0x780f0180,0xe007007,0xe00e380, 0xe0f0783,0x80e0000e,0xe000e0,0xe001,0xef000000,0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000, 0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xf830000,0x0,0x1e000000,0x0,0x0,0x10000,0x780c0000,0x3e38000,0xe0,0x0,0x0,0x0,0x0,0x0,0x3, 0xd580000,0x0,0x0,0xe038,0x1c,0xc000,0xf0400000,0x380e0038,0x702000,0x1ffc0,0xc0000,0x0,0x3ff80,0x606,0x0,0x30000600,0x0, 0x7f8c000,0x0,0xc001818,0x60,0xc0003,0xe0000700,0x1f8003f,0x7e000,0xfc001f80,0x73801ee,0x7c1c1c,0x38000,0x70000e00,0xe0001, 0xc0003800,0x700383e,0x7c0703c,0x3c078780,0xf0f01e1e,0x3c3c000,0xf0f87,0x70e00e,0x1c01c380,0x38380e07,0xe038,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x1c,0x1c7000,0xc380fff0,0xc0c00380,0x70000,0x70001c00,0x3dbc0070,0x0,0x0,0x701e0f,0xe0000,0x1e000380, 0x6e03800,0x7800000,0x781c0707,0x80e00000,0x0,0x0,0x4038,0xe00c03f,0x700e07,0x4380f0,0x38000700,0x700438,0x3801c00,0x381c0e, 0x1c000ec,0x1b8fc0e0,0xf03c1c03,0xc3c0f0e0,0x3c1e0000,0xe007007,0xe00e380,0xe070703,0xc1e0001e,0xe000e0,0xe001,0xc7000000, 0x0,0x700000,0x38,0x38,0x1c,0x0,0x700,0x1c0000,0x0,0x0,0x0,0x0,0x1c000000,0x0,0x0,0x0,0x70000e,0x1c000,0x0,0xe010000,0x0, 0x1c000000,0x10,0x20000,0x6c000,0xf0000000,0x3838000,0x1e0,0x0,0xf000f,0xf1e00,0x78f00000,0x0,0x3,0xdd80000,0x0,0x0,0xf078, 0x0,0xc001,0xe0000000,0x1c1c0038,0x700000,0x3c1e0,0xc0000,0x0,0x783c0,0x606,0x0,0x30000e00,0x0,0xff8c000,0x0,0xc00300c,0x60, 0xc0003,0xe0000000,0x1f8003f,0x7e000,0xfc001f80,0x73801ce,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x7e07078, 0x1e0f03c1,0xe0783c0f,0x781e000,0x1c0787,0x70e00e,0x1c01c380,0x383c1e07,0xff00e038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x878, 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, 0x1c7000,0xc301e630,0xc0c00380,0x70000,0xe0000e00,0xff00070,0x0,0x0,0xe01c07,0xe0000,0xe000380,0xce03800,0x7000000,0x701c0707, 0x600000,0x0,0x4000010,0x38,0x1c00e07f,0x80700e0e,0x38070,0x38000700,0xe00038,0x3801c00,0x381c1c,0x1c000ec,0x1b8ec0e0,0xe01c1c01, 0xc38070e0,0x1c1c0000,0xe007007,0x701c380,0xe078e01,0xc1c0003c,0xe00070,0xe003,0x83800000,0x7f,0x71f000,0x3e003e38,0x3f007ff, 0xe01f1c1c,0x7801fc00,0x3fc00701,0xe01c0077,0x8f071e00,0xf801c7c,0x7c700e,0x3e01fc03,0xfff8380e,0xe007700,0x73c0787,0x387ffc, 0x70000e,0x1c000,0x0,0xe000000,0x0,0x1c000000,0x10,0x20000,0xc2000,0xe0000000,0x3838000,0x3c0,0x0,0xf000f,0x78e00,0x70e00000, 0x0,0x3,0xc980fe0,0x1f0,0xf8000007,0xffc07070,0x0,0x3f801,0xc0000000,0x1e3c0038,0x700000,0x70070,0x7fc0000,0x0,0xe00e0,0x606, 0x1c0000,0x70007c00,0x380e,0xff8c000,0x0,0xc00300c,0x60,0xc0000,0x70000000,0x3fc007f,0x800ff001,0xfe003fc0,0x73801ce,0xe0001c, 0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807,0x7607070,0xe0e01c1,0xc0383807,0x700e000,0x1c0387,0x70e00e,0x1c01c380,0x381c1c07, 0xffc0e0f8,0x3f8007f,0xfe001,0xfc003f80,0x7f007e3,0xe003e001,0xf8003f00,0x7e000fc,0xfe001f,0xc003f800,0x7f00003c,0x38f0007, 0xc000f800,0x1f0003e0,0x7c0007,0x8003f0c3,0x80e0701c,0xe0381c0,0x70700387,0x1f01c00e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0xc0c00380,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03c07, 0x800e0000,0xe000380,0x1ce03800,0x7000000,0x701c0707,0x7003c0,0x780000,0x3c00001e,0x38,0x18006073,0x80700e0e,0x38070,0x38000700, 0xe00038,0x3801c00,0x381c38,0x1c000ee,0x3b8ee0e1,0xe01e1c01,0xc78078e0,0x1c1c0000,0xe007007,0x701c387,0xe03de00,0xe3800038, 0xe00070,0xe007,0x1c00000,0x1ff,0xc077f801,0xff807fb8,0xff807ff,0xe03fdc1d,0xfc01fc00,0x3fc00703,0xc01c007f,0xdf877f00,0x3fe01dfe, 0xff700e,0xff07ff03,0xfff8380e,0x700f700,0x71e0f03,0x80707ffc,0x70000e,0x1c000,0x0,0x1c000008,0x0,0x1c000000,0x10,0x20000, 0x82000,0xe0000000,0x7038000,0x80000380,0x2000040,0x7000e,0x38700,0xf1e00000,0x0,0x3,0xc183ff8,0x3fd,0xfc008007,0xffc038e0, 0x0,0xffc01,0xc0008008,0xe380038,0x380000,0xe3e38,0x1ffc0040,0x80000000,0x1cfc70,0x606,0x1c0000,0xe0007c00,0x380e,0xff8c000, 0x0,0xc00300c,0x8100060,0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0x73801ce,0xe0001c,0x38000,0x70000e00,0xe0001, 0xc0003800,0x7003807,0x77070f0,0xf1e01e3,0xc03c7807,0x8f00f080,0x83c0787,0x70e00e,0x1c01c380,0x380e3807,0xffe0e1c0,0xffe01ff, 0xc03ff807,0xff00ffe0,0x1ffc0ff7,0xf01ff807,0xfc00ff80,0x1ff003fe,0xfe001f,0xc003f800,0x7f0003fc,0x3bf801f,0xf003fe00,0x7fc00ff8, 0x1ff0007,0x8007fd83,0x80e0701c,0xe0381c0,0x70380707,0x7f80e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x1c,0x1c701f,0xfff1c600,0x618081c0,0x70000,0xe0000e00,0x3c00070,0x0,0x0,0xe03803,0x800e0000,0xe000380,0x18e03800, 0xf000000,0xf01c0707,0x7003c0,0x780000,0xfc00001f,0x80000078,0x301e6073,0x80700e1c,0x38038,0x38000700,0x1c00038,0x3801c00, 0x381c70,0x1c000e6,0x338ee0e1,0xc00e1c01,0xc70038e0,0x1c1c0000,0xe007007,0x701c387,0xe01dc00,0xf7800078,0xe00070,0xe00e,0xe00000, 0x3ff,0xe07ffc03,0xffc0fff8,0x1ffc07ff,0xe07ffc1d,0xfe01fc00,0x3fc00707,0x801c007f,0xdf877f80,0x7ff01fff,0x1fff00e,0xff07ff03, 0xfff8380e,0x700e380,0xe0e0e03,0x80707ffc,0x70000e,0x1c000,0x0,0x7ffc001c,0x0,0x1c000000,0x10,0x20000,0x82000,0xe0000000, 0x7038001,0xc0000780,0x70000e0,0x3800e,0x38700,0xe1c00000,0x0,0x3,0xc183ff8,0x7ff,0xfc01c007,0xffc03de0,0x0,0x1ffc01,0xc001c01c, 0xf780038,0x3c0000,0xcff18,0x380c00c1,0x80000000,0x18fe30,0x30c,0x1c0001,0xc0000e00,0x380e,0xff8c000,0x0,0xc00300c,0xc180060, 0xc0000,0x30000700,0x39c0073,0x800e7001,0xce0039c0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x877070e0, 0x71c00e3,0x801c7003,0x8e0071c0,0x1c380fc7,0x70e00e,0x1c01c380,0x380f7807,0x1e0e380,0x1fff03ff,0xe07ffc0f,0xff81fff0,0x3ffe0fff, 0xf03ffc0f,0xfe01ffc0,0x3ff807ff,0xfe001f,0xc003f800,0x7f0007fe,0x3bfc03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x800fff83,0x80e0701c, 0xe0381c0,0x70380707,0xffc0e01c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x1c701f, 0xfff1c600,0x7f8381e0,0x70000,0xc0000600,0xff00070,0x0,0x0,0x1c03803,0x800e0000,0xe000f00,0x38e03fe0,0xe000000,0xe00e0e07, 0x7003c0,0x780007,0xf0ffff87,0xf00000f0,0x307fe0f3,0xc0703c1c,0x38038,0x38000700,0x1c00038,0x3801c00,0x381ce0,0x1c000e6,0x338e70e1, 0xc00e1c01,0xc70038e0,0x3c1e0000,0xe007007,0x783c38f,0x8e01fc00,0x770000f0,0xe00038,0xe01c,0x700000,0x381,0xe07c1e07,0xc0c1e0f8, 0x3c1e0038,0xf07c1f,0xe001c00,0x1c0070f,0x1c0079,0xf3c7c380,0xf0781f07,0x83c1f00f,0xc10f0300,0x1c00380e,0x700e380,0xe0f1e03, 0xc0f00078,0x70000e,0x1c000,0x0,0xfff8003e,0x0,0x3c000000,0x10,0x20000,0xc6000,0xf0000000,0x7038003,0xe0000f00,0xf8001f0, 0x3801c,0x18300,0xe1800000,0x0,0x3,0xc187818,0x70f,0x9e03e000,0x7801dc0,0x1c,0x3cc401,0xc000efb8,0x7f7f0038,0x3f0000,0x1ce11c, 0x300c01c3,0x80000000,0x38c638,0x3fc,0x1c0003,0x80000600,0x380e,0xff8c000,0x0,0xc00300c,0xe1c0060,0xc0010,0x70000700,0x79e00f3, 0xc01e7803,0xcf0079e0,0xe1c038e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003, 0x8e0070e0,0x38381dc7,0x70e00e,0x1c01c380,0x38077007,0xf0e700,0x1c0f0381,0xe0703c0e,0x781c0f0,0x381e083e,0x787c0c1e,0xf03c1e0, 0x783c0f07,0x800e0001,0xc0003800,0x7000fff,0x3e1c078,0x3c0f0781,0xe0f03c1e,0x783c000,0x1e0f03,0x80e0701c,0xe0381c0,0x70380f07, 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, 0xc0000700,0x3dbc0070,0x0,0x0,0x1c03803,0x800e0000,0x1e01fe00,0x70e03ff8,0xe3e0001,0xe007fc07,0x80f003c0,0x78001f,0xc0ffff81, 0xfc0001e0,0x30e1e0e1,0xc07ff81c,0x38038,0x3ffe07ff,0xc1c0003f,0xff801c00,0x381de0,0x1c000e7,0x738e70e1,0xc00e1c03,0xc70038e0, 0x780f8000,0xe007007,0x383838d,0x8e00f800,0x7f0000e0,0xe00038,0xe000,0x0,0x200,0xf0780e07,0x8041c078,0x380e0038,0xe03c1e, 0xf001c00,0x1c0071e,0x1c0070,0xe1c783c0,0xe0381e03,0x8380f00f,0xe0000,0x1c00380e,0x381c380,0xe07bc01,0xc0e00078,0x70000e, 0x1c000,0x0,0x1c000061,0x0,0x38000000,0x10,0x20000,0x7c000,0x7c000000,0x703fc06,0x10000e00,0x18400308,0x1801c,0x1c381,0xc3800000, 0x0,0x0,0x7000,0xe0f,0xe061000,0x7801fc0,0x1c,0x38c001,0xc0007ff0,0x7fff0038,0x77c000,0x19c00c,0x301c0387,0x0,0x30c618,0xf0, 0x1c0007,0x600,0x380e,0x7f8c007,0x80000000,0xc001818,0x70e03fc,0x387f871f,0xe0e00700,0x70e00e1,0xc01c3803,0x870070e0,0xe1c038f, 0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001,0xc0003800,0x7003803,0x873870e0,0x71c00e3,0x801c7003,0x8e007070,0x703839c7,0x70e00e, 0x1c01c380,0x3807f007,0x70e700,0x10078200,0xf0401e08,0x3c10078,0x200f001c,0x3878041c,0x70380e0,0x701c0e03,0x800e0001,0xc0003800, 0x7001e0f,0x3c1e070,0x1c0e0381,0xc070380e,0x701c000,0x1c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80e07038,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600e600,0x7803f0,0x1,0xc0000700,0x718e0070,0x0,0x0,0x38038c3, 0x800e0000,0x3c01f800,0x60e03ffc,0xeff8001,0xc001f003,0xc1f003c0,0x7800fe,0xffff80,0x3f8003c0,0x60c0e0e1,0xc07fe01c,0x38038, 0x3ffe07ff,0xc1c07e3f,0xff801c00,0x381fe0,0x1c000e3,0x638e30e1,0xc00e1c07,0x870038ff,0xf00ff800,0xe007007,0x38381cd,0x9c007000, 0x3e0001e0,0xe0001c,0xe000,0x0,0x0,0x70780f0f,0x3c078,0x70070038,0x1e03c1c,0x7001c00,0x1c0073c,0x1c0070,0xe1c701c1,0xe03c1e03, 0xc780f00f,0xe0000,0x1c00380e,0x381c387,0xe03f801,0xc0e000f0,0x70000e,0x1c007,0xe0100000,0x1c0000cd,0x80000003,0xffc00000, 0x3ff,0x807ff000,0xe0,0x7fc00060,0x703fc0c,0xd8001e00,0x3360066c,0x1c018,0xc181,0x83000000,0x0,0x0,0x7000,0x300e07,0xe0cd800, 0xf000f80,0x1c,0x78c00f,0xff0038e0,0x3e00038,0xe1e000,0x19800c,0x383c070e,0x7fffc00,0x30fc18,0x0,0xffff80e,0x20e00,0x380e, 0x7f8c007,0x80000000,0xc001c38,0x38703ff,0xf87fff0f,0xcfe00f00,0x70e00e1,0xc01c3803,0x870070e0,0x1e1e078f,0xe1c0001f,0xff03ffe0, 0x7ffc0fff,0x800e0001,0xc0003800,0x700ff83,0x871870e0,0x71c00e3,0x801c7003,0x8e007038,0xe03871c7,0x70e00e,0x1c01c380,0x3803e007, 0x70e700,0x38000,0x70000e00,0x1c00038,0x7001c,0x38f00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7001c07,0x380e0f0,0x1e1e03c3, 0xc078780f,0xf01e000,0x3c0f03,0x80e0701c,0xe0381c0,0x701c0e07,0x80f07038,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0x3,0x8600ff00,0x1e00778,0x38000001,0xc0000700,0x21843fff,0xe0000000,0x0,0x38039e3,0x800e0000, 0x7c01fe00,0xe0e0203e,0xeffc001,0xc00ffe03,0xff700000,0x7f0,0x0,0x7f00380,0x618060e1,0xc07ffc1c,0x38038,0x3ffe07ff,0xc1c07e3f, 0xff801c00,0x381ff0,0x1c000e3,0x638e38e1,0xc00e1fff,0x870038ff,0xc003fe00,0xe007007,0x38381cd,0x9c00f800,0x3e0003c0,0xe0001c, 0xe000,0x0,0x0,0x7070070e,0x38038,0x70070038,0x1c01c1c,0x7001c00,0x1c00778,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0xfc000, 0x1c00380e,0x381c3c7,0x1e01f001,0xe1e001e0,0xf0000e,0x1e01f,0xf8300000,0x1c00019c,0xc0000003,0xffc00000,0x10,0x20000,0x700, 0x1ff000c0,0x703fc19,0xcc003c00,0x67300ce6,0xc038,0xc181,0x83000000,0x0,0x0,0x7e00,0x180e07,0xe19cc00,0x1e000f80,0x1c,0x70c00f, 0xff007070,0x3e00038,0xe0f000,0x19800c,0x1fec0e1c,0x7fffc00,0x30f818,0x0,0xffff81f,0xf003fc00,0x380e,0x3f8c007,0x80000000, 0x7f800ff0,0x1c3803f,0xe007fc00,0xff800e00,0x70e00e1,0xc01c3803,0x870070e0,0x1c0e070f,0xe1c0001f,0xff03ffe0,0x7ffc0fff,0x800e0001, 0xc0003800,0x700ff83,0x871c70e0,0x71c00e3,0x801c7003,0x8e00701d,0xc038e1c7,0x70e00e,0x1c01c380,0x3803e007,0x70e3c0,0x38000, 0x70000e00,0x1c00038,0x7001c,0x38e00038,0x3870070,0xe00e1c01,0xc00e0001,0xc0003800,0x7003c07,0x8380e0e0,0xe1c01c3,0x80387007, 0xe00e1ff,0xfe381b83,0x80e0701c,0xe0381c0,0x701e1e07,0x707878,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x1c,0x3,0xe007fe0,0x7800e3c,0x38000001,0xc0000700,0x1803fff,0xe0000000,0x0,0x70039c3,0x800e0000,0xf8000f80, 0xc0e0000e,0xf83c003,0xc01e0f01,0xff700000,0x7c0,0x0,0x1f00780,0x618061c0,0xe0701e1c,0x38038,0x38000700,0x1c07e38,0x3801c00, 0x381e78,0x1c000e3,0xe38e18e1,0xc00e1fff,0x70038ff,0xe0007f80,0xe007007,0x1c701dd,0x9c00f800,0x1c000780,0xe0000e,0xe000,0x0, 0x7f,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x7fc00,0x1c00380e, 0x1c381c7,0x1c01f000,0xe1c001c0,0xfe0000e,0xfe1f,0xfff00000,0x7ff003fc,0xe0000003,0xffc00000,0x10,0x20000,0x3800,0x3fc0180, 0x703803f,0xce007800,0xff381fe7,0x30,0x0,0xc0,0x0,0x0,0x3fe0,0xc0e07,0xfe3fce00,0x1c000700,0x1c,0x70c00f,0xff006030,0x1c00000, 0xe07800,0x19800c,0xfcc1c38,0x7fffc00,0x30d818,0x0,0xffff81f,0xf001f800,0x380e,0xf8c007,0x80000000,0x7f8007e0,0xe1c3fe,0x7fc00f, 0xf8001e00,0xe0701c0,0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700ff83,0x870c70e0, 0x71c00e3,0x801c7003,0x8e00700f,0x8038c1c7,0x70e00e,0x1c01c380,0x3801c007,0xf0e3e0,0x3ff807f,0xf00ffe01,0xffc03ff8,0x7ff03ff, 0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe383383,0x80e0701c, 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, 0x3c1e1c1c,0x38000001,0xc0000700,0x1803fff,0xe0000007,0xf8000000,0x7003803,0x800e0001,0xf0000381,0xc0e00007,0xf01e003,0x801c0700, 0x7c700000,0x7c0,0x0,0x1f00700,0x618061c0,0xe0700e1c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381e38,0x1c000e1,0xc38e1ce1, 0xc00e1ffc,0x70038e0,0xf0000780,0xe007007,0x1c701dd,0xdc01fc00,0x1c000780,0xe0000e,0xe000,0x0,0x1ff,0xf070070e,0x38038,0x7fff0038, 0x1c01c1c,0x7001c00,0x1c007f8,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3ff00,0x1c00380e,0x1c381cd,0x9c00e000,0xe1c003c0, 0xf80000e,0x3e18,0x3ff00000,0xffe007fd,0xf0000000,0x38000000,0x10,0x20000,0x1c000,0x3c0300,0x703807f,0xdf007801,0xff7c3fef, 0x80000000,0x0,0x3e0,0x7ffe7ff,0xff000000,0x1ff8,0x60e07,0xfe7fdf00,0x3c000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0xf03800, 0x19800c,0x1c38,0x1c07,0xf830cc18,0x0,0x1c0000,0x0,0x380e,0x18c007,0x80000000,0x0,0xe1cfe0,0x1fc003f,0x80003c00,0xe0701c0, 0xe0381c07,0x380e070,0x1c0e070e,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003, 0x8e007007,0x3981c7,0x70e00e,0x1c01c380,0x3801c007,0x1e0e0f8,0xfff81ff,0xf03ffe07,0xffc0fff8,0x1fff07ff,0xf8e0003f,0xff87fff0, 0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e1ff,0xfe386383,0x80e0701c,0xe0381c0,0x700e1c07, 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, 0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0003,0xe00001c3,0x80e00007,0xe00e007,0x80380380,0x700000,0x7f0,0x0,0x7f00700, 0x618061ff,0xe070071c,0x38038,0x38000700,0x1c00e38,0x3801c00,0x381c3c,0x1c000e1,0xc38e1ce1,0xc00e1c00,0x70038e0,0x700003c0, 0xe007007,0x1c701d8,0xdc03dc00,0x1c000f00,0xe00007,0xe000,0x0,0x3ff,0xf070070e,0x38038,0x7fff0038,0x1c01c1c,0x7001c00,0x1c007fc, 0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x3f00,0x1c00380e,0x1c381cd,0x9c01f000,0x73800780,0xfe0000e,0xfe10,0x7c00000,0x1c000ffb, 0xf8000000,0x38000000,0x10,0x20000,0x20000,0x1e0700,0x70380ff,0xbf80f003,0xfefe7fdf,0xc0000000,0x0,0x3f0,0x7ffe7ff,0xff000000, 0x1f8,0x30e07,0xfeffbf80,0x78000700,0x1c,0x70c001,0xc0006030,0x7fff0000,0x783800,0x1ce11c,0xe1c,0x1c07,0xf838ce38,0x0,0x1c0000, 0x0,0x380e,0x18c000,0x0,0x0,0x1c38c00,0x1800030,0x7800,0xfff01ff,0xe03ffc07,0xff80fff0,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00, 0xe0001,0xc0003800,0x7003803,0x870e70e0,0x71c00e3,0x801c7003,0x8e00700f,0x803b81c7,0x70e00e,0x1c01c380,0x3801c007,0xffe0e03c, 0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0fff,0xf8e0003f,0xff87fff0,0xfffe1fff,0xc00e0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3, 0x80387007,0xe00e000,0x38c383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f,0xffc0063c,0x40619c0f,0x30000001,0xc0000700,0x70,0x7,0xf8000000,0xe003803,0x800e0007,0xc00001c3, 0xfffc0007,0xe00e007,0x380380,0xf00000,0xfe,0xffff80,0x3f800700,0x618063ff,0xf070071c,0x38038,0x38000700,0x1c00e38,0x3801c00, 0x381c1e,0x1c000e0,0x38e0ee1,0xc00e1c00,0x70038e0,0x380001c0,0xe007007,0x1ef01d8,0xdc038e00,0x1c001e00,0xe00007,0xe000,0x0, 0x7c0,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0079e,0x1c0070,0xe1c701c1,0xc01c1c01,0xc700700e,0x780,0x1c00380e, 0xe701cd,0x9c01f000,0x73800f00,0xe0000e,0xe000,0x0,0x1c0007f7,0xf0000000,0x70000000,0x10,0x20000,0x0,0xe0e00,0x703807f,0x7f01e001, 0xfdfc3fbf,0x80000000,0x0,0x7f0,0x0,0x0,0x3c,0x18e07,0x7f7f00,0xf0000700,0x1c,0x70c001,0xc0007070,0x1c00000,0x3e7000,0xcff18, 0x3ffc070e,0x1c07,0xf818c630,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x3870000,0xe000fc00,0x380f000,0x1fff83ff,0xf07ffe0f, 0xffc1fff8,0x3fff0ffe,0x1c0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003803,0x870770e0,0x71c00e3,0x801c7003,0x8e00701d, 0xc03f01c7,0x70e00e,0x1c01c380,0x3801c007,0xffc0e01c,0x3e0387c0,0x70f80e1f,0x1c3e038,0x7c071e1c,0xe00038,0x70000,0xe0001c00, 0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x398383,0x80e0701c,0xe0381c0,0x70073807,0x701ce0, 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, 0x70,0x0,0x0,0x1c003c07,0x800e000f,0x1c3,0xfffc0007,0xe00e007,0x380380,0xe00000,0x1f,0xc0ffff81,0xfc000700,0x618063ff,0xf070070e, 0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0e,0x1c000e0,0x38e0ee1,0xe01e1c00,0x78078e0,0x380001c0,0xe007007,0xee01f8,0xfc078f00, 0x1c001c00,0xe00003,0x8000e000,0x0,0x700,0x7070070e,0x38038,0x70000038,0x1c01c1c,0x7001c00,0x1c0070e,0x1c0070,0xe1c701c1, 0xc01c1c01,0xc700700e,0x380,0x1c00380e,0xe700ed,0xb803f800,0x77800f00,0x70000e,0x1c000,0x0,0xe0003f7,0xe0000000,0x70000000, 0x10,0x20000,0x1c0e0,0xe1c00,0x703803f,0x7e01c000,0xfdf81fbf,0x0,0x0,0x3f0,0x0,0x0,0x1c,0x1ce07,0x3f7e00,0xf0000700,0x1c, 0x70c001,0xc00038e0,0x1c00038,0xf7000,0xe3e38,0x3ffc0387,0x1c00,0x1cc770,0x0,0x1c0000,0x0,0x380e,0x18c000,0x0,0x3ffc,0x70e0001, 0xe001fe00,0x780e000,0x1fff83ff,0xf07ffe0f,0xffc1fff8,0x3fff0ffe,0xe0001c,0x38000,0x70000e00,0xe0001,0xc0003800,0x7003807, 0x70770f0,0xf1e01e3,0xc03c7807,0x8f00f038,0xe03e03c7,0x70e00e,0x1c01c380,0x3801c007,0xff00e00e,0x38038700,0x70e00e1c,0x1c38038, 0x70071c1c,0xe00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003803,0x8380e0e0,0xe1c01c3,0x80387007,0xe00e000,0x3b0383,0x80e0701c, 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, 0xc0de03,0xe0000001,0xc0000700,0x70,0x0,0x0,0x1c001c07,0xe001e,0x1c3,0xfffc0007,0x600e00e,0x380380,0xe00000,0x7,0xf0ffff87, 0xf0000000,0x60c0e380,0x7070070e,0x38070,0x38000700,0xe00e38,0x3801c00,0x381c0f,0x1c000e0,0x38e06e0,0xe01c1c00,0x38070e0, 0x1c0001c0,0xe007007,0xee00f8,0xf80f0700,0x1c003c00,0xe00003,0x8000e000,0x0,0x700,0x70780f0f,0x3c078,0x70000038,0x1e03c1c, 0x7001c00,0x1c0070f,0x1c0070,0xe1c701c1,0xe03c1e03,0xc780f00e,0x380,0x1c00380e,0xe700f8,0xf807bc00,0x3f001e00,0x70000e,0x1c000, 0x0,0xe0001ff,0xc0000000,0x70000000,0x10,0x20000,0x33110,0xe0e00,0x383801f,0xfc03c000,0x7ff00ffe,0x0,0x0,0x3e0,0x0,0x0,0x1c, 0x38e07,0x1ffc01,0xe0000700,0x1c,0x78c001,0xc0007ff0,0x1c00038,0x7c000,0x70070,0x1c3,0x80001c00,0xe00e0,0x0,0x1c0000,0x0, 0x380e,0x18c000,0x0,0x0,0xe1c0001,0xe0010700,0x780e000,0x1c038380,0x70700e0e,0x1c1c038,0x78070e0e,0xe0001c,0x38000,0x70000e00, 0xe0001,0xc0003800,0x7003807,0x7037070,0xe0e01c1,0xc0383807,0x700e070,0x701c0387,0x70e00e,0x1c01c380,0x3801c007,0xe00e,0x38038700, 0x70e00e1c,0x1c38038,0x70071c1c,0xf00038,0x70000,0xe0001c00,0xe0001,0xc0003800,0x7003c07,0x8380e0f0,0x1e1e03c3,0xc078780f, 0xf01e007,0x803e0783,0x80e0701c,0xe0381c0,0x7003f007,0x80f00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x6,0x1800061c,0xc0de01,0xc0000000,0xc0000e00,0x70,0xf0000,0x3c00,0x38001c0f,0xe003c,0x3c0,0xe0000e,0x701e00e, 0x3c0780,0x1e003c0,0x780000,0xfc00001f,0x80000000,0x60e1e780,0x78700f07,0x4380f0,0x38000700,0xf00e38,0x3801c00,0xc0781c07, 0x81c000e0,0x38e07e0,0xe03c1c00,0x380f0e0,0x1e0003c0,0xe00780f,0xee00f0,0x780e0780,0x1c007800,0xe00001,0xc000e000,0x0,0x700, 0xf0780e07,0x8041c078,0x38020038,0xe03c1c,0x7001c00,0x1c00707,0x801c0070,0xe1c701c0,0xe0381e03,0x8380f00e,0x80380,0x1c003c1e, 0x7e00f8,0xf80f1e00,0x3f003c00,0x70000e,0x1c000,0x0,0xf0100f7,0x80078000,0x700078f0,0x10,0x7ff000,0x61208,0x1e0700,0x383800f, 0x78078000,0x3de007bc,0x0,0x0,0x0,0x0,0x0,0x401c,0x70e0f,0xf7803,0xc0000700,0x1c,0x38c001,0xc000efb8,0x1c00038,0x1e000,0x3c1e0, 0xc1,0x80000000,0x783c0,0x0,0x0,0x0,0x3c1e,0x18c000,0x0,0x0,0xc180003,0x60000300,0xd80e010,0x3c03c780,0x78f00f1e,0x1e3c03c, 0x70039c0e,0x70041c,0x38000,0x70000e00,0xe0001,0xc0003800,0x700380f,0x703f070,0x1e0e03c1,0xc078380f,0x701e0e0,0x381c0787, 0x80f0f01e,0x1e03c3c0,0x7801c007,0xe00e,0x38078700,0xf0e01e1c,0x3c38078,0x700f1c1c,0x78041c,0x1038020,0x70040e00,0x800e0001, 0xc0003800,0x7001c07,0x380e070,0x1c0e0381,0xc070380e,0x701c007,0x801e0703,0xc1e0783c,0xf0781e0,0xf003f007,0x80e00fc0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xe,0x1801867c,0xc0cf83,0xe0000000,0xe0000e00, 0x70,0xf0000,0x3c00,0x38000f1e,0xe0070,0x180780,0xe0603e,0x783c01e,0x1e0f01,0x7c003c0,0x780000,0x3c00001e,0x700,0x307fe700, 0x38701e07,0xc1c383e0,0x38000700,0x7c1e38,0x3801c00,0xe0f01c03,0x81c000e0,0x38e03e0,0x78781c00,0x1e1e0e0,0xe180780,0xe003c1e, 0x7c00f0,0x781e03c0,0x1c007000,0xe00001,0xc000e000,0x0,0x783,0xf07c1e07,0xc0c1e0f8,0x3e0e0038,0xf07c1c,0x7001c00,0x1c00703, 0xc01e0070,0xe1c701c0,0xf0781f07,0x83c1f00e,0xe0f80,0x1e003c3e,0x7e00f8,0xf80e0e00,0x3f003800,0x70000e,0x1c000,0x0,0x7830077, 0xf0000,0x700078f0,0x10,0x20000,0x41208,0xc03c0380,0x3c38007,0x70070000,0x1dc003b8,0x0,0x0,0x0,0x0,0x0,0x707c,0x6070f,0x86077003, 0x80000700,0x1c,0x3ec401,0xc001c01c,0x1c00038,0xf000,0x1ffc0,0x40,0x80000000,0x3ff80,0x0,0x0,0x0,0x3e3e,0x18c000,0x0,0x0, 0x8100006,0x60000300,0x1980f070,0x3801c700,0x38e0071c,0xe3801c,0x70039c0e,0x7c1c1c,0x38000,0x70000e00,0xe0001,0xc0003800, 0x700383e,0x701f03c,0x3c078780,0xf0f01e1e,0x3c3c1c0,0x1c3f0f03,0xc1e0783c,0xf0781e0,0xf001c007,0xe81e,0x3c1f8783,0xf0f07e1e, 0xfc3c1f8,0x783f1e3e,0x187c0c1f,0x703e0e0,0x7c1c0f83,0x800e0001,0xc0003800,0x7001e0f,0x380e078,0x3c0f0781,0xe0f03c1e,0x783c007, 0x801e0f03,0xc3e0787c,0xf0f81e1,0xf003f007,0xc1e00fc0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x1c,0xe,0x3801fff8,0x6187ff,0xe0000000,0xe0000e00,0x70,0xf0000,0x3c00,0x38000ffe,0x1fff0ff,0xfe1fff80,0xe07ffc,0x3ffc01c, 0x1fff01,0xff8003c0,0x780000,0x4000010,0x700,0x301e6700,0x387ffe03,0xffc3ffc0,0x3fff0700,0x3ffe38,0x383ffe0,0xfff01c03,0xc1fff8e0, 0x38e03e0,0x7ff81c00,0x1ffe0e0,0xf1fff80,0xe003ffe,0x7c00f0,0x781c01c0,0x1c00ffff,0xe00001,0xc000e000,0x0,0x3ff,0x707ffc03, 0xffc0fff8,0x1ffe0038,0x7ffc1c,0x707fff0,0x1c00701,0xc00ff070,0xe1c701c0,0x7ff01fff,0x1fff00e,0xfff00,0xff81fee,0x7e00f0, 0x781e0f00,0x1e007ffc,0x70000e,0x1c000,0x0,0x3ff003e,0xf0000,0xe00070e0,0x60830010,0x20000,0x41208,0xfffc01c0,0x1fffe03,0xe00ffff0, 0xf8001f0,0x0,0x0,0x0,0x0,0x0,0x7ff8,0xc07fd,0xfe03e007,0xffc00700,0x1c,0x1ffc1f,0xffc08008,0x1c00038,0x7000,0x7f00,0x0,0x0, 0xfe00,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0x6,0x60000700,0x19807ff0,0x3801c700,0x38e0071c,0xe3801c,0x70039c0f,0xf03ffc1f, 0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ffc,0x701f03f,0xfc07ff80,0xfff01ffe,0x3ffc080,0x83fff03,0xffe07ffc,0xfff81ff, 0xf001c007,0xeffc,0x1ffb83ff,0x707fee0f,0xfdc1ffb8,0x3ff70ff7,0xf83ffc0f,0xff01ffe0,0x3ffc07ff,0x83fff87f,0xff0fffe1,0xfffc0ffe, 0x380e03f,0xf807ff00,0xffe01ffc,0x3ff8007,0x803ffe01,0xfee03fdc,0x7fb80ff,0x7001e007,0xffc00780,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1c,0xc,0x3801fff0,0x7f83fe,0x70000000,0xe0000e00,0x0,0xf0000,0x3c00,0x700007fc, 0x1fff0ff,0xfe1ffe00,0xe07ff8,0x1ff801c,0xffe01,0xff0003c0,0x780000,0x0,0x700,0x38000f00,0x3c7ffc01,0xff83ff80,0x3fff0700, 0x1ffc38,0x383ffe0,0x7fe01c01,0xe1fff8e0,0x38e03e0,0x3ff01c00,0xffc0e0,0x71fff00,0xe001ffc,0x7c00f0,0x783c01e0,0x1c00ffff, 0xe00000,0xe000e000,0x0,0x1ff,0x7077f801,0xff807fb8,0xffc0038,0x3fdc1c,0x707fff0,0x1c00701,0xe007f070,0xe1c701c0,0x3fe01dfe, 0xff700e,0x7fe00,0xff80fee,0x3c0070,0x703c0780,0x1e007ffc,0x70000e,0x1c000,0x0,0x1fe001c,0xe0000,0xe000e1c0,0x71c78010,0x20000, 0x21318,0xfff800c0,0xfffe01,0xc00ffff0,0x70000e0,0x0,0x0,0x0,0x0,0x0,0x3ff0,0x1803fd,0xfe01c007,0xffc00700,0x1c,0xffc1f,0xffc00000, 0x1c00038,0x7000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x3ff7,0x8018c000,0x0,0x0,0xc,0x60000e00,0x31803fe0,0x7801ef00,0x3de007bc, 0xf7801e,0xf003fc0f,0xf01ff81f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83ff8,0x701f01f,0xf803ff00,0x7fe00ffc,0x1ff8000, 0x67fe01,0xffc03ff8,0x7ff00ff,0xe001c007,0xeff8,0xffb81ff,0x703fee07,0xfdc0ffb8,0x1ff70ff7,0xf81ff807,0xfe00ffc0,0x1ff803ff, 0x3fff87f,0xff0fffe1,0xfffc07fc,0x380e01f,0xf003fe00,0x7fc00ff8,0x1ff0000,0x37fc00,0xfee01fdc,0x3fb807f,0x7001e007,0x7f800780, 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, 0x0,0xe0000,0x3c00,0x700001f0,0x1fff0ff,0xfe07f800,0xe01fe0,0x7e0038,0x3f800,0xfc0003c0,0x700000,0x0,0x700,0x18000e00,0x1c7ff000, 0x7e03fe00,0x3fff0700,0x7f038,0x383ffe0,0x1f801c00,0xf1fff8e0,0x38e01e0,0xfc01c00,0x3f80e0,0x787fc00,0xe0007f0,0x7c00f0,0x387800f0, 0x1c00ffff,0xe00000,0xe000e000,0x0,0xfc,0x7071f000,0x3f003e38,0x3f00038,0x1f1c1c,0x707fff0,0x1c00700,0xf003f070,0xe1c701c0, 0x1f801c7c,0x7c700e,0x1f800,0x3f8078e,0x3c0070,0x707803c0,0x1c007ffc,0x70000e,0x1c000,0x0,0x7c0008,0x1e0000,0xe000e1c0,0x71c30010, 0x20000,0x1e1f0,0x3fe00020,0x3ffe00,0x800ffff0,0x2000040,0x0,0x0,0x0,0x0,0x0,0xfc0,0x3001f0,0x78008007,0xffc00700,0x1c,0x3f81f, 0xffc00000,0x1c00038,0x407000,0x0,0x0,0x0,0x0,0x0,0xffff800,0x0,0x39c7,0x18c000,0x0,0x0,0x18,0x60001c00,0x61801f80,0x7000ee00, 0x1dc003b8,0x77000e,0xe001f80f,0xf007e01f,0xff83fff0,0x7ffe0fff,0xc1fff03f,0xfe07ffc0,0xfff83fc0,0x700f007,0xe000fc00,0x1f8003f0, 0x7e0000,0xe1f800,0x7f000fe0,0x1fc003f,0x8001c007,0xe7f0,0x7e380fc,0x701f8e03,0xf1c07e38,0xfc703c1,0xe003f001,0xf8003f00, 0x7e000fc,0x3fff87f,0xff0fffe1,0xfffc03f8,0x380e00f,0xc001f800,0x3f0007e0,0xfc0000,0x61f800,0x78e00f1c,0x1e3803c,0x7001c007, 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, 0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xc000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0, 0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000, 0x70000e,0x1c000,0x0,0x0,0x1c0000,0xe000c180,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, 0x0,0x38,0x70e000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x2000,0x0,0x1f,0xf8003800,0x7fe00000,0x0,0x0,0x0,0x0,0x4000, 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, 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, 0x0,0x1c0000,0x0,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0xe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e000, 0x0,0x0,0x0,0x0,0x0,0xe00000,0x7000e000,0x0,0x0,0x0,0x0,0x0,0x1c00,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x1c000000, 0x70000e,0x1c000,0x0,0x0,0x1c0001,0xe001c380,0x10,0x20000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, 0x0,0x38,0x7fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x3000,0x0,0x1f,0xf8007000,0x7fe00000,0x0,0x0,0x0,0x0,0x6000, 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, 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, 0x0,0x380000,0x1,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x1c00000,0x0,0x0,0x3c18000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf000, 0x0,0x0,0x0,0x0,0x0,0xfe0000,0x380fe000,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x1c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x38000000, 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, 0x38,0x1f8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x18c000,0x1800,0x0,0x0,0x6000e000,0x1800000,0x0,0x0,0x0,0x0,0x3000,0x0, 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, 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, 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, 0x0,0x0,0x0,0xfe0000,0xfe000,0x0,0x0,0x0,0x0,0x0,0x607800,0x0,0x3c00000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x0,0x78000000, 0x3f800e,0x3f8000,0x0,0x0,0x300043,0xc0018200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xc000, 0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3800,0x0,0x11800,0x0,0x0,0x6001ff00,0x1800000,0x0,0x0,0x0,0x0,0x23000,0x0,0x0, 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, 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, 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, 0xfe000,0x0,0x0,0x0,0x0,0x0,0x7ff000,0x0,0x7f800000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf8000000,0x3f800e,0x3f8000,0x0, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x7f000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xf0000000,0xf800e,0x3e0000,0x0,0x0,0x7f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x1fc000,0x0,0x7e000000,0x0,0x0,0x1c00,0x7000,0x0,0x0,0x0,0x3,0xc0000000,0xe,0x0, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 29x57 font const unsigned int font29x57[29*57*256/32] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0xc0000000,0x0,0x7c00,0xf80,0x7e000,0x0,0x7c00000,0xf80000,0x7e000000,0x0,0x0,0x1f00,0x3e0,0x1f800,0x0,0x0,0x0,0x3,0xe0000000, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,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, 0x1f0000,0x7e00000,0xf838001f,0xf80001f,0xf0000000,0x0,0x3e00,0x1f00,0x7e000,0x3e1f000,0x3e00000,0x1f00000,0x7e00003e,0x1f000000, 0x3e0,0xe0000f80,0x7c0,0x1f800,0x3e0e00,0x7c3e000,0x0,0x1,0xf0000000,0xf800003f,0x1f0f,0x800001f0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1e0000,0x1e0000,0xff00001,0xfe38001f,0xf80003f, 0xf8000000,0x0,0x1e00,0x1e00,0xff000,0x3e1f000,0x1e00000,0x1e00000,0xff00003e,0x1f000000,0x7f8,0xe0000780,0x780,0x3fc00,0x7f8e00, 0x7c3e000,0x0,0x0,0xf0000000,0xf000007f,0x80001f0f,0x800001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000,0x3c0000,0x1e780003,0xfff8001f,0xf80003c,0x78000000,0x0,0xf00,0x3c00,0x1e7800, 0x3e1f000,0xf00000,0x3c00001,0xe780003e,0x1f000000,0xfff,0xe00003c0,0xf00,0x79e00,0xfffe00,0x7c3e000,0x0,0x0,0x78000001,0xe00000f3, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x78000,0x780000,0x3c3c0003,0x8ff0001f,0xf800078,0x3c000000,0x0,0x780,0x7800,0x3c3c00,0x3e1f000,0x780000,0x7800003,0xc3c0003e, 0x1f000000,0xe3f,0xc00001e0,0x1e00,0xf0f00,0xe3fc00,0x7c3e000,0x0,0x0,0x3c000003,0xc00001e1,0xe0001f0f,0x80000780,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,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,0xfc00,0x7e000,0xfe000,0x0,0x3c000,0xf00000,0x781e0003, 0x83e0001f,0xf800070,0x1c000000,0x0,0x3c0,0xf000,0x781e00,0x3e1f000,0x3c0000,0xf000007,0x81e0003e,0x1f000000,0xe0f,0x800000f0, 0x3c00,0x1e0780,0xe0f800,0x7c3e000,0x0,0x0,0x1e000007,0x800003c0,0xf0001f0f,0x80000f00,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf8000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f00000,0x3e000,0x3e00000,0x0,0x78,0x3c000000,0x0,0x1f000,0x3e0, 0x3e000,0x0,0x1f000000,0x3e0000,0x3e000000,0x0,0x0,0x7c00,0xf8,0xf800,0x0,0x0,0x0,0xf,0x80000000,0x1f00001f,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,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x781c0000,0x38,0xe000000,0x0,0x0,0x380e0,0x0, 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, 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, 0x0,0x0,0xf80000,0x7c000,0x3e00000,0xf0380000,0x70,0x1c000000,0x0,0xf800,0x7c0,0x3e000,0x0,0xf800000,0x7c0000,0x3e000000, 0x0,0x3c0,0xe0003e00,0x1f0,0xf800,0x3c0e00,0x0,0x0,0x7,0xc0000000,0x3e00001f,0x0,0x7c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,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, 0xf8,0xf8000,0x1c000,0x0,0x0,0x0,0x0,0x1f,0xc0000000,0x1ff8,0xff00,0x0,0x0,0x3fe000,0x0,0x1fc00001,0xfe000000,0x0,0x0,0x0, 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, 0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x780000,0x1,0xe0000000,0x0,0x780000,0x3,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000, 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, 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, 0x0,0x0,0x1ff,0x1f0f8,0x0,0xff000,0x0,0x0,0x0,0x3f,0xff00000f,0x80000000,0xfe0,0x3f80,0xf00,0x0,0x0,0x0,0x1,0xf8000003,0xe0000000, 0x1c00,0xe000,0xe00,0x0,0x0,0x0,0x0,0x0,0x3c,0x78000000,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000, 0x7f0000,0x0,0x1fc07000,0x0,0x0,0x0,0x0,0x0,0x3f800,0x780000,0x78000,0x7f00001,0xfc38001f,0xf800070,0x1c000000,0x0,0x7800, 0x780,0x7f000,0x3e1f000,0x7800000,0x780000,0x7f00003e,0x1f0003f0,0x7f0,0xe0001e00,0x1e0,0x1fc00,0x7f0e00,0x7c3e000,0x0,0x3, 0xc0000000,0x3c00003f,0x80001f0f,0x80000078,0x1e0000,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,0x0,0x0,0x780000,0x3c1e0000,0x1e078000,0x30000000,0x3ff,0xc00001e0,0xf0, 0x78000,0x1c000,0x0,0x0,0x0,0x0,0x1e0007f,0xf000007e,0x1ffff,0x7ffe0,0x1f80,0x3ffff80,0xfff803,0xfffff800,0xfff80007,0xff800000, 0x0,0x0,0x0,0x0,0x1ffe00,0x0,0xfe0003,0xfff80000,0x3ffe01ff,0xe00003ff,0xffe01fff,0xff0003ff,0xe01e0007,0x803ffff0,0xfff80, 0x3c000fc0,0x7800001f,0x8003f07e,0x1e000f,0xfe0007ff,0xf00003ff,0x8007ffe0,0x1fff8,0x7fffffe,0xf0003c1,0xe000079e,0xf1f,0x1f3e0, 0x1f01ff,0xfff8003f,0xf003c000,0x7fe0,0x3f00,0x0,0x3c0000,0x1,0xe0000000,0x0,0x780000,0xf,0xfe000000,0x78000,0x3c00,0xf000, 0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0xfc0000f0,0x3fe00,0x0,0x0,0xfff00,0x0,0x0,0x3fe000, 0x0,0x0,0x0,0x1dc0,0x0,0x3fff00,0x0,0x3ffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff1c07ff,0x3c0f001e,0x3c000000, 0x0,0x0,0x1e3c0,0xf80007c,0x0,0x780000,0x0,0xfff8000,0x3e00,0x1f00000,0x7ff,0xc001f0f8,0x0,0x3ffc00,0x0,0x0,0x0,0x3f,0xff00003f, 0xe0000000,0x3ff8,0xffe0,0x1e00,0x0,0xfffc00,0x0,0x7,0xf800000f,0xf8000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000, 0x3f800001,0xfc00003f,0xf80000ff,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc, 0xfc00,0x3c001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x0,0x7ff8f0f0,0x3c0780,0x1e03c00,0xf01e000,0x783e0001,0xf01e0000,0xffe00, 0x3c0000,0xf0000,0x7700001,0xfe38001f,0xf800070,0x1c000000,0x0,0x3c00,0xf00,0x77000,0x3e1f000,0x3c00000,0xf00000,0x7700003e, 0x1f0000f8,0xc0007f8,0xe0000f00,0x3c0,0x1dc00,0x7f8e00,0x7c3e000,0x0,0x1,0xe0000000,0x7800003b,0x80001f0f,0x800000f0,0x1e0000, 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, 0x0,0x0,0x780000,0x3c1e0000,0x1e070000,0x300001f0,0x7ff,0xc00001e0,0x1e0,0x7c000,0x1c000,0x0,0x0,0x0,0x0,0x3c000ff,0xf80007fe, 0x3ffff,0x801ffff8,0x1f80,0x3ffff80,0x3fff803,0xfffff801,0xfffc000f,0xffc00000,0x0,0x0,0x0,0x0,0x7fff80,0x0,0xfe0003,0xffff0000, 0xffff01ff,0xfc0003ff,0xffe01fff,0xff000fff,0xf01e0007,0x803ffff0,0xfff80,0x3c001f80,0x7800001f,0xc007f07e,0x1e001f,0xff0007ff, 0xfc0007ff,0xc007fffc,0x3fffc,0x7fffffe,0xf0003c1,0xf0000f9e,0xf0f,0x8003e1e0,0x1e01ff,0xfff8003f,0xf001e000,0x7fe0,0x3f00, 0x0,0x1e0000,0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x1fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x3de0,0x0,0x7fff80,0x0,0xfffff80, 0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xe7bc07ff,0x3e1f000f,0x78000000,0x0,0x0,0xf780,0x7800078,0x0,0x780000,0x180000, 0x1fff8000,0x1e00,0x1e0003c,0xfff,0xc001f0f8,0x0,0x7ffe00,0x0,0x0,0x0,0x3f,0xff00007f,0xf0000000,0x3ffc,0xfff0,0x3c00,0x0, 0x7fffc00,0x0,0x7,0xf800003f,0xfe000000,0x1c00,0xe000,0xe00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xe00001ff, 0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000fc00,0x3c003ffe,0x1fff0, 0xfff80,0x7ffc00,0x3ffe000,0x0,0xfffce0f0,0x3c0780,0x1e03c00,0xf01e000,0x781e0001,0xe01e0000,0x3fff00,0x1e0000,0x1e0000,0xf780003, 0xcf78001f,0xf800078,0x3c000000,0x0,0x1e00,0x1e00,0xf7800,0x3e1f000,0x1e00000,0x1e00000,0xf780003e,0x1f0000fc,0x7c000f3d, 0xe0000780,0x780,0x3de00,0xf3de00,0x7c3e000,0x0,0x0,0xf0000000,0xf000007b,0xc0001f0f,0x800001e0,0x1e0000,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,0x0,0x0,0x780000, 0x3c1e0000,0x1e0f0000,0x300007fc,0xfff,0xc00001e0,0x1e0,0x3c000,0x1c000,0x0,0x0,0x0,0x0,0x3c001ff,0xfc001ffe,0x3ffff,0xc01ffffc, 0x3f80,0x3ffff80,0x7fff803,0xfffff803,0xfffe001f,0xffe00000,0x0,0x0,0x0,0x0,0xffff80,0x7f800,0xfe0003,0xffff8001,0xffff01ff, 0xff0003ff,0xffe01fff,0xff001fff,0xf01e0007,0x803ffff0,0xfff80,0x3c003f00,0x7800001f,0xc007f07f,0x1e003f,0xff8007ff,0xff000fff, 0xe007ffff,0x7fffc,0x7fffffe,0xf0003c0,0xf0000f1e,0xf07,0x8003c1f0,0x3e01ff,0xfff8003f,0xf001e000,0x7fe0,0x7f80,0x0,0xe0000, 0x1,0xe0000000,0x0,0x780000,0x1f,0xfe000000,0x78000,0x3c00,0xf000,0x7800003,0xffe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0, 0x0,0x0,0x0,0x0,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x3fff80,0x0,0x0,0xffe000,0x0,0x0,0x0,0x78f0,0x0,0xffff80,0x0,0x3fffff80,0x1f, 0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc7f80070,0x3e1f0007,0x70000000,0x0,0x0,0x7700,0x7c000f8,0x0,0x780000,0x180000, 0x3fff8000,0x1f00,0x3e0003c,0x1f03,0xc001f0f8,0x0,0x703f00,0x0,0x0,0x0,0x3f,0xff0000f0,0xf8000000,0x303e,0xc0f8,0x7800,0x0, 0xffffc00,0x0,0x7,0x3800003e,0x3e000000,0x1c00,0xe000,0x3c00,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00000f,0xe00001ff, 0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000fe00,0x3c007fff,0x3fff8, 0x1fffc0,0xfffe00,0x7fff000,0x1,0xffffc0f0,0x3c0780,0x1e03c00,0xf01e000,0x781f0003,0xe01e0000,0x3fff80,0xe0000,0x3c0000,0x1e3c0003, 0x8ff0001f,0xf80003c,0x78000000,0x0,0xe00,0x3c00,0x1e3c00,0x3e1f000,0xe00000,0x3c00001,0xe3c0003e,0x1f00007f,0xf8000e3f,0xc0000380, 0xf00,0x78f00,0xe3fc00,0x7c3e000,0x0,0x0,0x70000001,0xe00000f1,0xe0001f0f,0x800003c0,0x1e0000,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,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0000, 0x30000ffe,0xf80,0xc00001e0,0x3c0,0x1e000,0x101c040,0x0,0x0,0x0,0x0,0x78003f0,0x7e001ffe,0x3f807,0xe01f00fe,0x3f80,0x3ffff80, 0x7e01803,0xfffff007,0xe03f003f,0x3f00000,0x0,0x0,0x0,0x0,0xfc0fc0,0x3ffe00,0xfe0003,0xffffc003,0xf81f01ff,0xff8003ff,0xffe01fff, 0xff003f01,0xf01e0007,0x803ffff0,0xfff80,0x3c007e00,0x7800001f,0xc007f07f,0x1e007e,0xfc007ff,0xff801f83,0xf007ffff,0x800fc07c, 0x7fffffe,0xf0003c0,0xf0000f0f,0x1e07,0xc007c0f8,0x7c01ff,0xfff8003c,0xf000,0x1e0,0xffc0,0x0,0xf0000,0x1,0xe0000000,0x0,0x780000, 0x3e,0x0,0x78000,0x3c00,0xf000,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0x800000f0,0x1f80, 0x0,0x0,0x7e0780,0x0,0x0,0x1f82000,0x0,0x0,0x0,0x7070,0x0,0x1f80f80,0x0,0x7fffff80,0x1f,0xffff8000,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x1,0xc3f80070,0x3f3f0007,0xf0000000,0x0,0x0,0x7f00,0x3e001f0,0x0,0x780000,0x180000,0x7f018000,0xf80,0x7c0003c,0x3e00, 0x4001f0f8,0xfe00,0x400f00,0x0,0x0,0x0,0x7f000000,0xe0,0x38000000,0x1e,0x38,0x7800,0x0,0x1ffe1c00,0x0,0x0,0x38000078,0xf000000, 0x1c00,0xe000,0x7f800,0xf000,0x1fc000,0xfe0000,0x7f00000,0x3f800001,0xfc00001f,0xf00001ff,0xffc03f81,0xf007ffff,0xc03ffffe, 0x1fffff0,0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf800fe00,0x3c00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800, 0x3,0xf07fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x780f8007,0xc01e0000,0x7e0fc0,0xf0000,0x3c0000,0x1c1c0003,0x87f0001f,0xf80003f, 0xf8000000,0x0,0xf00,0x3c00,0x1c1c00,0x3e1f000,0xf00000,0x3c00001,0xc1c0003e,0x1f00003f,0xc0000e1f,0xc00003c0,0xf00,0x70700, 0xe1fc00,0x7c3e000,0x0,0x0,0x78000001,0xe00000e0,0xe0001f0f,0x800003c0,0x1e0000,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,0x0,0x0,0x780000,0x3c1e0000,0x3c0f0001,0xff801e0f, 0x1f00,0x1e0,0x3c0,0x1e000,0x3c1c1e0,0x0,0x0,0x0,0x0,0x78007c0,0x1f001f9e,0x3c001,0xf010003e,0x7780,0x3c00000,0xf800000,0xf007, 0xc01f007c,0x1f80000,0x0,0x0,0x0,0x0,0xe003e0,0x7fff00,0x1ef0003,0xc007e007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x301e0007, 0x80007800,0x780,0x3c00fc00,0x7800001f,0xe00ff07f,0x1e00f8,0x3e00780,0x1fc03e00,0xf807801f,0xc01f001c,0xf000,0xf0003c0,0xf0000f0f, 0x1e03,0xc00f8078,0x780000,0xf0003c,0xf000,0x1e0,0x1f3e0,0x0,0x78000,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0, 0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1f,0xf0,0xf80,0x0,0x0,0xf80180,0x0,0x0,0x1e00000, 0x0,0x0,0x0,0xe038,0x0,0x3e00380,0x0,0xfe0f0000,0x0,0xf0000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0xc0f00070,0x3b370003,0xe0000000, 0x0,0x0,0x3e00,0x1e001e0,0x0,0x780000,0x180000,0x7c000000,0x780,0x780003c,0x3c00,0x0,0x7ffc0,0x780,0x0,0x0,0x3,0xffe00000, 0x1c0,0x3c000000,0xe,0x38,0xf000,0x0,0x3ffe1c00,0x0,0x0,0x38000078,0xf000000,0x1c00,0xe000,0x7f000,0xf000,0x3de000,0x1ef0000, 0xf780000,0x7bc00003,0xde00001e,0xf00003e7,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 0xe0001e03,0xfc00fe00,0x3c01f007,0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x7,0xc01f80f0,0x3c0780,0x1e03c00,0xf01e000,0x78078007, 0x801e0000,0x7803c0,0x78000,0x780000,0x380e0003,0x81e00000,0x1f,0xf0000000,0x0,0x780,0x7800,0x380e00,0x0,0x780000,0x7800003, 0x80e00000,0x1ff,0x80000e07,0x800001e0,0x1e00,0xe0380,0xe07800,0x0,0x0,0x0,0x3c000003,0xc00001c0,0x70000000,0x780,0x1e0000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x3c0e0007,0xfff01c07,0x1e00,0x1e0,0x780,0xf000,0x3e1c3e0,0x0,0x0,0x0,0x0,0xf0007c0,0x1f00181e,0x20000, 0xf000001f,0xf780,0x3c00000,0x1f000000,0x1f00f,0x800f8078,0xf80000,0x0,0x0,0x0,0x0,0x8003e0,0x1fc0f80,0x1ef0003,0xc001e007, 0x800101e0,0x7e003c0,0x1e00,0x7800,0x101e0007,0x80007800,0x780,0x3c00f800,0x7800001e,0xe00ef07f,0x801e00f0,0x1e00780,0x7c03c00, 0x78078007,0xc01e0004,0xf000,0xf0003c0,0x78001e0f,0x1e03,0xe00f807c,0xf80000,0x1f0003c,0x7800,0x1e0,0x3e1f0,0x0,0x3c000,0x1, 0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000,0x0,0x0,0x0,0x0,0x0, 0x1e,0xf0,0x780,0x0,0x0,0x1f00080,0x0,0x0,0x3c00000,0x0,0x0,0x0,0x1e03c,0x0,0x3c00080,0x0,0xf80f0000,0x0,0x1f0000,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x70,0x3bf70003,0xe0000000,0x0,0x0,0x3e00,0x1f003e0,0x0,0x780000,0x180000,0x78000000,0x7c0,0xf80003c, 0x3c00,0x0,0x1f01f0,0x780,0x0,0x0,0xf,0x80f80000,0x1c0,0x1c000000,0xe,0x38,0x1e000,0x0,0x7ffe1c00,0x0,0x0,0x380000f0,0x7800000, 0x1c00,0xe000,0x7fc00,0xf000,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x80007800,0x10078000,0x3c0000, 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00ff00,0x3c01e003,0xc00f001e,0x7800f0,0x3c00780,0x1e003c00, 0x7,0x800f00f0,0x3c0780,0x1e03c00,0xf01e000,0x7807c00f,0x801e0000,0xf803c0,0x3c000,0xf00000,0x780f0000,0x0,0x7,0xc0000000, 0x0,0x3c0,0xf000,0x780f00,0x0,0x3c0000,0xf000007,0x80f00000,0x7ff,0xc0000000,0xf0,0x3c00,0x1e03c0,0x0,0x0,0x0,0x0,0x1e000007, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x3c1e001f,0xfff03803,0x80001e00,0x1e0,0x780,0xf000,0xf9cf80, 0x0,0x0,0x0,0x0,0xf000780,0xf00001e,0x0,0xf800000f,0xe780,0x3c00000,0x1e000000,0x1e00f,0x78078,0x7c0000,0x0,0x0,0x0,0x0,0x1e0, 0x3f003c0,0x1ef0003,0xc000f00f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780,0x3c01f000,0x7800001e,0xe00ef07f, 0x801e01f0,0x1e00780,0x3c07c00,0x78078003,0xc03e0000,0xf000,0xf0003c0,0x78001e0f,0x1e01,0xf01f003c,0xf00000,0x3e0003c,0x7800, 0x1e0,0x7c0f8,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000,0x0,0x0,0x0,0x0,0x0,0x0,0x3c000, 0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x1e00000,0x0,0x0,0x3c00000,0x0,0x8,0x40,0x0,0x7e0000,0x7c00000,0x1,0xf00f0000, 0x0,0x3e0000,0x0,0x3f,0xfc0,0xfc3f0,0xfc3f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0,0xf003c0,0x0,0x0,0x180000,0xf8000000, 0x3c0,0xf00003c,0x3c00,0x0,0x3c0078,0x7ff80,0x0,0x0,0x1e,0x3c0000,0x1c0,0x1c000000,0xe,0xf0,0x0,0x0,0x7ffe1c00,0x0,0x0,0x380000f0, 0x7800000,0x1c00,0xe000,0x3c00,0x0,0x3de000,0x1ef0000,0xf780000,0x7bc00003,0xde00001e,0xf00003c7,0x8000f800,0x78000,0x3c0000, 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00ff00,0x3c03e003,0xc01f001e,0xf800f0,0x7c00780,0x3e003c00, 0xf,0x800f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803c00f,0x1fffc0,0xf001e0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e0000,0x781e003f,0xfff03803, 0x80001e00,0x1e0,0xf80,0xf000,0x3dde00,0x0,0x0,0x0,0x0,0xf000f00,0x780001e,0x0,0x7800000f,0x1e780,0x3c00000,0x3e000000,0x3e00f, 0x780f0,0x7c0000,0x0,0x0,0x0,0x0,0x1e0,0x7c001e0,0x3ef8003,0xc000f00f,0x1e0,0xf003c0,0x1e00,0xf000,0x1e0007,0x80007800,0x780, 0x3c03e000,0x7800001e,0xf01ef07b,0xc01e01e0,0xf00780,0x3e07800,0x3c078003,0xe03c0000,0xf000,0xf0003c0,0x78001e0f,0x1e00,0xf01e003e, 0x1f00000,0x3c0003c,0x7800,0x1e0,0x78078,0x0,0x0,0x1,0xe0000000,0x0,0x780000,0x3c,0x0,0x78000,0x0,0x0,0x7800000,0x1e00000, 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, 0xe70000,0x7800000,0x1,0xe00f0000,0x0,0x3c0000,0x0,0x3f,0xfc0,0xfc1f0,0x1f83f0,0x0,0x0,0x0,0x70,0x39e70000,0x0,0x0,0x0,0x0, 0xf807c0,0x0,0x0,0x180000,0xf0000000,0x3e0,0x1f00003c,0x3e00,0x0,0x70001c,0x3fff80,0x0,0x0,0x38,0xe0000,0x1c0,0x1c000078, 0x1c,0x1fe0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x7df000,0x3ef8000,0x1f7c0000,0xfbe00007, 0xdf00003c,0x780003c7,0x8000f000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f780, 0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0xf80f0,0x3c0780,0x1e03c00,0xf01e000,0x7803e01f,0x1ffff8,0xf001e0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x781e003e,0x30703803,0x80001e00,0x1e0,0xf00,0x7800,0xff800,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e, 0x0,0x7800000f,0x3c780,0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x2000000,0x800000,0x1e0,0x78000e0,0x3c78003, 0xc000f01e,0x1e0,0xf803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x701cf07b,0xc01e01e0,0xf00780,0x1e07800, 0x3c078001,0xe03c0000,0xf000,0xf0003c0,0x7c003e0f,0x1e00,0xf83e001e,0x1e00000,0x7c0003c,0x3c00,0x1e0,0xf807c,0x0,0x0,0x1fe0001, 0xe1fc0000,0x7f00003,0xf8780007,0xf000003c,0x7f0,0x783f0,0x0,0x0,0x7800000,0x1e00000,0x3e0f8000,0xfc00007,0xf8000007,0xf00001fc, 0xf,0xc0003fc0,0x3c000,0x0,0x0,0x0,0x0,0x0,0x1e,0xf0,0x780,0x0,0x0,0x3c00000,0x0,0x0,0x3c00000,0x0,0x18,0xc0,0x0,0x1818000, 0x7800000,0x1,0xe00f0000,0x0,0x7c0000,0x0,0x1f,0x80001f80,0x7c1f8,0x1f83e0,0x0,0x0,0x0,0x70,0x38c70007,0xf8000000,0x7f03, 0xf0000000,0x0,0x780780,0x0,0x0,0xfe0000,0xf0000000,0x1e0,0x1e00003c,0x3f00,0x0,0xe07f0e,0x7fff80,0x0,0x0,0x70,0x70000,0x1c0, 0x1c000078,0x3c,0x1fc0,0x0,0x0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800000,0x1c00,0xe000,0xe00,0x0,0x78f000,0x3c78000,0x1e3c0000, 0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, 0xf80f780,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0xf,0x1f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801e01e,0x1ffffc, 0xf007e0,0x3fc000,0x1fe0000,0xff00000,0x7f800003,0xfc00001f,0xe0000fc0,0xfc00007f,0xfe0,0x7f00,0x3f800,0x1fc000,0x0,0x0,0x0, 0x1,0xf000001f,0x80000ff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x1f80000,0x1fc1e000,0x0,0x0,0x0,0x0,0x1e1fc0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,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, 0x781c007c,0x30003803,0x80001f00,0x1e0,0xf00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x1e000f00,0x780001e,0x0,0x7800000f,0x3c780, 0x3c00000,0x3c000000,0x3c00f,0x780f0,0x3c0000,0x0,0x0,0x1e000000,0xf00000,0x3e0,0xf0000e0,0x3c78003,0xc000f01e,0x1e0,0x7803c0, 0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c0f8000,0x7800001e,0x701cf079,0xe01e01e0,0xf00780,0x1e07800,0x3c078001,0xe03c0000, 0xf000,0xf0003c0,0x3c003c0f,0x3e00,0x787c001f,0x3e00000,0xf80003c,0x3c00,0x1e0,0x1f003e,0x0,0x0,0x1fffc001,0xe7ff0000,0x3ffe000f, 0xfe78003f,0xfc001fff,0xfe001ffc,0xf0078ffc,0x1ffc00,0x7ff000,0x7800f80,0x1e0000f,0x7f1fc01e,0x3ff0001f,0xfe00079f,0xfc0007ff, 0x3c003c7f,0xf001fff8,0x1fffff0,0x3c003c0,0xf0000f1e,0xf1f,0x7c1f0,0x1f00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3c00000,0x100000, 0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7800000,0x1,0xe00f0000,0x1000000,0xf80000,0x40000002,0xf,0x80001f00,0x7e0f8,0x1f07c0, 0x0,0x0,0x0,0x70,0x38c7003f,0xff000000,0xff8f,0xf8000100,0xffffe,0x7c0f80,0x0,0x0,0x3ffc000,0xf0000020,0x1001f0,0x3c00003c, 0x1f80,0x0,0x1c3ffc7,0x7c0780,0x0,0x0,0xe3,0xff038000,0xe0,0x38000078,0x78,0x1ff0,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0, 0x7800000,0x1c00,0xe000,0xe00,0xf000,0x78f000,0x3c78000,0x1e3c0000,0xf1e00007,0x8f00003c,0x78000787,0x8001e000,0x78000,0x3c0000, 0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00, 0x4000200f,0x3f80f0,0x3c0780,0x1e03c00,0xf01e000,0x7801f03e,0x1ffffe,0xf01fe0,0x3fff800,0x1fffc000,0xfffe0007,0xfff0003f, 0xff8001ff,0xfc003ff3,0xfe0003ff,0xe0007ff8,0x3ffc0,0x1ffe00,0xfff000,0x3ff80001,0xffc0000f,0xfe00007f,0xf000003f,0xf8003c7f, 0xe0003ffc,0x1ffe0,0xfff00,0x7ff800,0x3ffc000,0x1f80000,0xfff1c03c,0x3c01e0,0x1e00f00,0xf007800,0x781f0001,0xf01e7ff0,0x7c0007c, 0x0,0x0,0x0,0x0,0x0,0x0,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, 0x3c1e003f,0xfffff078,0x30003803,0x80000f00,0x1e0,0x1f00,0x7800,0x7f000,0x1e0000,0x0,0x0,0x0,0x3c000f00,0x780001e,0x0,0x7800000f, 0x78780,0x3c00000,0x3c000000,0x7c00f,0x780f0,0x3c0007,0xe000003f,0x0,0xfe000000,0xfe0000,0x3c0,0x1f000070,0x7c7c003,0xc000f01e, 0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c1f0000,0x7800001e,0x783cf079,0xe01e03c0,0xf00780,0x1e0f000,0x3c078001, 0xe03c0000,0xf000,0xf0003c0,0x3c003c07,0x81f03c00,0x7c7c000f,0x87c00000,0xf00003c,0x1e00,0x1e0,0x3e001f,0x0,0x0,0x3fffe001, 0xefff8000,0x7fff001f,0xff78007f,0xfe001fff,0xfe003ffe,0xf0079ffe,0x1ffc00,0x7ff000,0x7801f00,0x1e0000f,0xffbfe01e,0x7ff8003f, 0xff0007bf,0xfe000fff,0xbc003cff,0xf803fffc,0x1fffff0,0x3c003c0,0x78001e1e,0xf0f,0x800f80f0,0x1e00ff,0xffe0001e,0xf0,0x780, 0x0,0x0,0x3c00000,0x380000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1008000,0x7800000,0x3,0xe00f0000,0x3800000,0xf00000,0xe0000007, 0xf,0x80001f00,0x3e0f8,0x1e07c0,0x0,0x0,0x0,0x70,0x3807007f,0xff800000,0x1ffdf,0xfc000380,0xffffe,0x3e1f00,0x0,0x0,0xfffe000, 0xf0000030,0x3800f8,0x7c00003c,0xfc0,0x0,0x18780c3,0xf00780,0x80100,0x0,0xc3,0xffc18000,0xf0,0x78000078,0xf0,0xf0,0x0,0x3c003c0, 0xfffe1c00,0x0,0x0,0x380000f0,0x7800801,0x1c00,0xe000,0x1e00,0xf000,0xf8f800,0x7c7c000,0x3e3e0001,0xf1f0000f,0x8f80007c,0x7c000787, 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078001,0xe03c000f, 0x1e00078,0xf0003c0,0x78001e00,0xe000701f,0x3fc0f0,0x3c0780,0x1e03c00,0xf01e000,0x7800f87c,0x1e007f,0xf07e00,0x7fffc00,0x3fffe001, 0xffff000f,0xfff8007f,0xffc003ff,0xfe007ff7,0xff0007ff,0xf000fffc,0x7ffe0,0x3fff00,0x1fff800,0x3ff80001,0xffc0000f,0xfe00007f, 0xf00000ff,0xf8003cff,0xf0007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x1f80001,0xfffb803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001, 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, 0x0,0x0,0x0,0x0,0x0,0x780000,0x3c1e003f,0xfffff078,0x30001c07,0xf80,0x1e0,0x1e00,0x3c00,0xff800,0x1e0000,0x0,0x0,0x0,0x3c001e00, 0x3c0001e,0x0,0x7800001e,0x70780,0x3c00000,0x78000000,0x78007,0x800f00f0,0x3e0007,0xe000003f,0x3,0xfe000000,0xff8000,0x7c0, 0x1e000070,0x783c003,0xc001f01e,0x1e0,0x7803c0,0x1e00,0x1e000,0x1e0007,0x80007800,0x780,0x3c3e0000,0x7800001e,0x3838f079, 0xe01e03c0,0x780780,0x1e0f000,0x1e078001,0xe03c0000,0xf000,0xf0003c0,0x3c007c07,0x81f03c00,0x3ef80007,0x87800000,0x1f00003c, 0x1e00,0x1e0,0x7c000f,0x80000000,0x0,0x3ffff001,0xffffc000,0xffff003f,0xff7800ff,0xff001fff,0xfe007ffe,0xf007bffe,0x1ffc00, 0x7ff000,0x7803e00,0x1e0000f,0xffffe01e,0xfff8007f,0xff8007ff,0xff001fff,0xbc003dff,0xf807fffc,0x1fffff0,0x3c003c0,0x78001e0f, 0x1e07,0xc01f00f0,0x1e00ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7c00000,0x7c0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1018000,0x7800000, 0x3,0xc00f0000,0x7c00000,0x1f00001,0xf000000f,0x80000007,0xc0003e00,0x1e07c,0x3e0780,0x0,0x0,0x0,0x70,0x380700ff,0xff800000, 0x3ffff,0xfe0007c0,0xffffe,0x1e1e00,0x0,0x780000,0x1fffe000,0xf0000078,0x7c0078,0x7800003c,0xff0,0x0,0x38e0003,0x80f00780, 0x180300,0x0,0x1c3,0x81e1c000,0x7f,0xf0000078,0x1e0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x380000f0,0x7800c01,0x80001c00, 0xe000,0x603e00,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x7800078,0x3c000f87,0x8001e000,0x78000,0x3c0000,0x1e00000, 0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f3c0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f01,0xf000f81e, 0x7bc0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007878,0x1e001f,0xf0f800,0x7fffe00,0x3ffff001,0xffff800f,0xfffc007f,0xffe003ff, 0xff007fff,0xff800fff,0xf001fffe,0xffff0,0x7fff80,0x3fffc00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00001ff,0xfc003dff,0xf000ffff, 0x7fff8,0x3fffc0,0x1fffe00,0xffff000,0x1f80003,0xffff803c,0x3c01e0,0x1e00f00,0xf007800,0x780f0001,0xe01ffffc,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,0x0,0x0,0x0,0x0,0x0,0x780000, 0x3c1e003f,0xfffff078,0x30001e0f,0x300780,0x1e0,0x1e00,0x3c00,0x3dde00,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf800003e, 0xf0780,0x3dfc000,0x783f8000,0xf8007,0xc01f00f0,0x3e0007,0xe000003f,0x1f,0xfc000000,0x7ff000,0xf80,0x3e007c70,0x783c003,0xc001e03c, 0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007,0x80007800,0x780,0x3c7c0000,0x7800001e,0x3878f078,0xf01e03c0,0x780780,0x1e0f000,0x1e078001, 0xe03e0000,0xf000,0xf0003c0,0x1e007807,0x83f03c00,0x3ef00007,0xcf800000,0x3e00003c,0xf00,0x1e0,0xf80007,0xc0000000,0x0,0x3e01f801, 0xfe07e001,0xf80f007e,0x7f801f8,0x1f801fff,0xfe00fc0f,0xf007f83f,0x1ffc00,0x7ff000,0x7807c00,0x1e0000f,0x87e1e01f,0xe0fc00fc, 0xfc007f8,0x1f803f03,0xfc003df0,0x3807e03c,0x1fffff0,0x3c003c0,0x78003e0f,0x1e03,0xe03e00f8,0x3e00ff,0xffe0001e,0xf0,0x780, 0x0,0x0,0x7800000,0xfe0000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0x1818000,0x7c00000,0x3,0xc00f0000,0xfe00000,0x3e00003,0xf800001f, 0xc0000007,0xc0003e00,0x1e03c,0x3c0f80,0x0,0x0,0x0,0x70,0x380700fc,0x7800000,0x7c1fe,0x3e000fe0,0xffffe,0x1f3e00,0x0,0x780000, 0x3f98e000,0xf000003c,0xfcf8007c,0xf800003c,0x3ffc,0x0,0x31c0001,0x80f00f80,0x380700,0x0,0x183,0x80e0c000,0x3f,0xe0000078, 0x3c0,0x38,0x0,0x3c003c0,0xfffe1c00,0x0,0x0,0x38000078,0xf000e01,0xc003ffe0,0x1fff00,0x7ffc00,0xf000,0xf07800,0x783c000,0x3c1e0001, 0xe0f0000f,0x7800078,0x3c000f07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00, 0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf801f01e,0xf3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78007cf8, 0x1e000f,0x80f0f000,0x7c03f00,0x3e01f801,0xf00fc00f,0x807e007c,0x3f003e0,0x1f80707f,0x8f801f80,0xf003f03f,0x1f81f8,0xfc0fc0, 0x7e07e00,0x3ff80001,0xffc0000f,0xfe00007f,0xf00003ff,0xfc003fc1,0xf801f81f,0x800fc0fc,0x7e07e0,0x3f03f00,0x1f81f800,0x1f80007, 0xe07f003c,0x3c01e0,0x1e00f00,0xf007800,0x780f8003,0xe01fe07e,0x3e000f8,0x0,0x0,0x0,0x0,0x0,0x0,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,0x3f,0xfffff078,0x30000ffe,0x1f007c0,0x0,0x1e00, 0x3c00,0xf9cf80,0x1e0000,0x0,0x0,0x0,0x78001e00,0x3c0001e,0x0,0xf00000fc,0x1e0780,0x3fff800,0x78ffe000,0xf0003,0xe03e00f0, 0x3e0007,0xe000003f,0x7f,0xe01fffff,0xf00ffc00,0x1f80,0x3c01ff70,0x783c003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x1e0007, 0x80007800,0x780,0x3cfc0000,0x7800001e,0x3c78f078,0xf01e03c0,0x780780,0x3e0f000,0x1e078003,0xc01f0000,0xf000,0xf0003c0,0x1e007807, 0x83f83c00,0x1ff00003,0xcf000000,0x3e00003c,0xf00,0x1e0,0x0,0x0,0x0,0x20007801,0xfc03e003,0xe003007c,0x3f803e0,0x7c0003c, 0xf807,0xf007e00f,0x3c00,0xf000,0x780f800,0x1e0000f,0x87e1f01f,0x803c00f8,0x7c007f0,0xf803e01,0xfc003f80,0x80f8004,0x3c000, 0x3c003c0,0x3c003c0f,0x1e03,0xe03e0078,0x3c0000,0x7c0001e,0xf0,0x780,0x0,0x0,0x3ffff800,0x1ff0000,0x0,0x7800000,0x0,0x18, 0xc0,0x0,0x1818000,0x3e00000,0x3,0xc00f0000,0x1ff00000,0x3e00007,0xfc00003f,0xe0000003,0xc0003c00,0xf03c,0x3c0f00,0x0,0x0, 0x0,0x70,0x380701f0,0x800000,0x780fc,0x1e001ff0,0x7c,0xf3c00,0x0,0x780000,0x7e182000,0xf000001f,0xfff00ffc,0xffc0003c,0x3cfe, 0x0,0x31c0001,0x80f01f80,0x780f00,0x0,0x183,0x80e0c000,0xf,0x80000078,0x780,0x38,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x38000078, 0xf000f01,0xe003ffe0,0x1fff00,0x7ff800,0xf000,0xf07800,0x783c000,0x3c1e0001,0xe0f0000f,0x78000f8,0x3e000f07,0x8003c000,0x78000, 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f1e0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, 0x78000f00,0x7c03e01e,0x1e3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78003cf0,0x1e0007,0x80f1e000,0x4000f00,0x20007801,0x3c008, 0x1e0040,0xf00200,0x780403f,0x7803e00,0x3007c00f,0x803e007c,0x1f003e0,0xf801f00,0x780000,0x3c00000,0x1e000000,0xf00007f0, 0x3e003f00,0x7801f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e003c,0x3c01e0,0x1e00f00,0xf007800,0x78078003, 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, 0x0,0x0,0x0,0x0,0x0,0x780000,0x0,0xf078007c,0x300007fc,0x7e00fe0,0x0,0x1e00,0x3c00,0x3e1c3e0,0x1e0000,0x0,0x0,0x0,0xf0001e00, 0x3c0001e,0x1,0xf000fff8,0x1e0780,0x3fffe00,0x79fff000,0x1f0001,0xfffc00f0,0x7e0007,0xe000003f,0x3ff,0x801fffff,0xf003ff80, 0x3f00,0x3c03fff0,0xf01e003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3df80000,0x7800001e, 0x1c70f078,0x781e03c0,0x780780,0x3c0f000,0x1e078007,0xc01f8000,0xf000,0xf0003c0,0x1e007807,0x83f83c00,0xfe00003,0xff000000, 0x7c00003c,0x780,0x1e0,0x0,0x0,0x0,0x7c01,0xf801f007,0xc00100f8,0x1f803c0,0x3c0003c,0x1f003,0xf007c00f,0x80003c00,0xf000, 0x783f000,0x1e0000f,0x3c0f01f,0x3e01f0,0x3e007e0,0x7c07c00,0xfc003f00,0xf0000,0x3c000,0x3c003c0,0x3c003c0f,0x1e01,0xf07c007c, 0x7c0000,0xfc0001e,0xf0,0x780,0x0,0x0,0x3ffff000,0x3838000,0x0,0x7800000,0x0,0x18,0xc0,0x0,0xff0000,0x3f00000,0x3,0xc00fff00, 0x38380000,0x7c0000e,0xe000070,0x70000001,0xe0003c00,0xf01e,0x780e00,0x0,0x0,0x0,0x0,0x1e0,0x0,0x780f8,0xf003838,0xfc,0xffc00, 0x0,0x780000,0x7c180000,0xf000000f,0xffe00fff,0xffc0003c,0x783f,0x80000000,0x6380000,0xc0f83f80,0xf81f00,0x0,0x303,0x80e06000, 0x0,0x78,0xf00,0x78,0x0,0x3c003c0,0x7ffe1c00,0x0,0x0,0x3800003c,0x3e000f81,0xf003ffe0,0x1fff00,0x1fc000,0xf000,0x1e03c00, 0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e000f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000, 0x3c000001,0xe0001e00,0x3c0f0f0,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3e07c01e,0x1e3c0f0,0x3c0780,0x1e03c00, 0xf01e000,0x78003ff0,0x1e0007,0x80f1e000,0xf80,0x7c00,0x3e000,0x1f0000,0xf80000,0x7c0001e,0x3c07c00,0x10078007,0x803c003c, 0x1e001e0,0xf000f00,0x780000,0x3c00000,0x1e000000,0xf00007c0,0x1e003e00,0x7c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00, 0xf,0x801f003c,0x3c01e0,0x1e00f00,0xf007800,0x7807c007,0xc01f801f,0x1f001f0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0xe078003c,0x300001f0,0x3f801ff0,0x0, 0x3c00,0x1e00,0x3c1c1e0,0x1e0000,0x0,0x0,0x0,0xf0001e0f,0x3c0001e,0x3,0xe000fff0,0x3c0780,0x3ffff00,0x7bfff800,0x1e0000,0x7ff00078, 0x7e0007,0xe000003f,0x1ffc,0x1fffff,0xf0007ff0,0x7e00,0x3c07c3f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000, 0x1fffff,0x80007800,0x780,0x3ffc0000,0x7800001e,0x1ef0f078,0x781e03c0,0x780780,0x7c0f000,0x1e07801f,0x800ff000,0xf000,0xf0003c0, 0xf00f807,0x83b83c00,0xfc00001,0xfe000000,0xf800003c,0x780,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0xc00000f0,0xf80780,0x3c0003c, 0x1e001,0xf007c007,0x80003c00,0xf000,0x787e000,0x1e0000f,0x3c0f01f,0x1e01e0,0x1e007c0,0x3c07800,0x7c003f00,0xf0000,0x3c000, 0x3c003c0,0x3e007c07,0x80003c00,0xf8f8003c,0x780000,0xf80001e,0xf0,0x780,0x0,0x0,0x7ffff000,0x601c000,0x3,0xffff0000,0x0, 0xfff,0xf8007fff,0xc0000000,0x7e003c,0x1fe0000,0xc0003,0xc00fff00,0x601c0000,0xf800018,0x70000c0,0x38000001,0xe0007800,0x701e, 0x701e00,0x0,0x0,0x0,0x0,0x1e0,0x6,0x700f8,0xf00601c,0xf8,0x7f800,0x0,0x780000,0xf8180000,0xf000000f,0x87c00fff,0xffc0003c, 0xf01f,0xc0000000,0x6380000,0xc07ff780,0x1f03e03,0xfffffe00,0x303,0x81c06000,0x0,0x1ffff,0xfe001e00,0x180f8,0x0,0x3c003c0, 0x3ffe1c00,0x3f00000,0x0,0x3800003f,0xfe0007c0,0xf8000000,0x18000000,0xc0000006,0x1f000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e, 0x3c000f0,0x1e001f07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f0f0, 0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f0f801e,0x3c3c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007, 0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07c00,0xf0007,0x8078003c,0x3c001e0,0x1e000f00,0x780000,0x3c00000, 0x1e000000,0xf0000f80,0x1f003e00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0xf,0x3f003c,0x3c01e0,0x1e00f00,0xf007800, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe078003f,0xb0000000,0xfc003cf0,0x0,0x3c00,0x1e00,0x101c040,0x1e0000,0x0,0x0,0x1, 0xe0001e1f,0x83c0001e,0x7,0xe000fff0,0x3c0780,0x3c03f80,0x7fc0fc00,0x1e0000,0xfff80078,0xfe0007,0xe000003f,0x7fe0,0x1fffff, 0xf0000ffc,0xfc00,0x780f81f0,0xf01e003,0xffff003c,0x1e0,0x3c03ff,0xffc01fff,0xfe03c000,0x1fffff,0x80007800,0x780,0x3ffc0000, 0x7800001e,0x1ef0f078,0x3c1e03c0,0x780780,0x1fc0f000,0x1e07ffff,0x7ff00,0xf000,0xf0003c0,0xf00f007,0xc3b87c00,0x7c00001,0xfe000000, 0xf800003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xf000f007,0x800000f0,0xf80780,0x1e0003c,0x1e001,0xf0078007,0x80003c00,0xf000,0x78fc000, 0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0,0x3c07800,0x7c003e00,0xf0000,0x3c000,0x3c003c0,0x1e007807,0x80003c00,0x7df0003c,0x780000, 0x1f00001e,0xf0,0x780,0x0,0x0,0x7800000,0xe7ce000,0x3,0xffff0000,0x0,0xfff,0xf8007fff,0xc0000000,0x1f0,0xffe000,0x1c0003, 0xc00fff00,0xe7ce0000,0xf800039,0xf38001cf,0x9c000000,0xe0007800,0x780e,0x701c00,0x0,0x0,0x0,0x0,0x1e0,0x7,0xf0078,0xf00e7ce, 0x1f0,0x7f800,0x0,0x780000,0xf0180000,0xf000000e,0x1c0001f,0xe000003c,0xf007,0xe0000000,0x6380000,0xc03fe780,0x3e07c03,0xfffffe00, 0x303,0xffc06000,0x0,0x1ffff,0xfe003ffe,0x1fff0,0x0,0x3c003c0,0x1ffe1c00,0x3f00000,0x7,0xffc0001f,0xfc0003e0,0x7c000001,0xfc00000f, 0xe000007f,0x1e000,0x1e03c00,0xf01e000,0x780f0003,0xc078001e,0x3c000f0,0x1e001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0, 0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e, 0x783c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78001fe0,0x1e0007,0x80f1e000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c07800, 0xf0003,0xc078001e,0x3c000f0,0x1e000780,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c03c003,0xc01e001e,0xf000f0, 0x7800780,0x3c003c00,0xf,0x7f003c,0x3c01e0,0x1e00f00,0xf007800,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1,0xe070001f,0xf8000007, 0xf0007cf8,0x7800000,0x3c00,0x1e00,0x1c000,0x1e0000,0x0,0x0,0x1,0xe0001e1f,0x83c0001e,0xf,0xc000fff8,0x780780,0x2000f80,0x7f803e00, 0x3e0003,0xfffe007c,0x1fe0000,0x0,0x3ff00,0x0,0x1ff,0x8001f000,0x780f00f0,0x1f00f003,0xffffc03c,0x1e0,0x3c03ff,0xffc01fff, 0xfe03c00f,0xf81fffff,0x80007800,0x780,0x3ffe0000,0x7800001e,0xee0f078,0x3c1e03c0,0x7807ff,0xff80f000,0x1e07fffe,0x3ffe0, 0xf000,0xf0003c0,0xf00f003,0xc7bc7800,0xfc00000,0xfc000001,0xf000003c,0x3c0,0x1e0,0x0,0x0,0x0,0x3c01,0xe000f80f,0x800001e0, 0xf80f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x79f8000,0x1e0000f,0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003e00, 0xf0000,0x3c000,0x3c003c0,0x1e007807,0x81e03c00,0x7df0003e,0xf80000,0x3e00003e,0xf0,0x7c0,0xfc000,0x80000000,0x7800000,0x1e7cf000, 0x3,0xffff0000,0x0,0x18,0xc0,0x0,0xf80,0x7ffc00,0x380003,0xc00fff01,0xe7cf0000,0x1f000079,0xf3c003cf,0x9e000000,0xe0007000, 0x380e,0xe01c00,0x0,0x0,0x0,0x0,0x1e0,0x3,0x800f0078,0xf01e7cf,0x3e0,0x3f000,0x0,0x780000,0xf018001f,0xfff8001e,0x1e0000f, 0xc000003c,0xf003,0xe0000000,0x6380000,0xc00fc780,0x7c0f803,0xfffffe00,0x303,0xfe006000,0x0,0x1ffff,0xfe003ffe,0x1ffe0,0x0, 0x3c003c0,0xffe1c00,0x3f00000,0x7,0xffc00007,0xf00001f0,0x3e00001f,0xfc0000ff,0xe00007ff,0x3e000,0x3e01e00,0x1f00f000,0xf8078007, 0xc03c003e,0x1e001e0,0xf001e07,0xff83c000,0x7ffff,0x803ffffc,0x1ffffe0,0xfffff00,0xf00000,0x7800000,0x3c000001,0xe000fff8, 0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000fc0, 0x1e0007,0x80f1f000,0x780,0x3c00,0x1e000,0xf0000,0x780000,0x3c0001e,0x3c0f800,0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000, 0x3c00000,0x1e000000,0xf0000f00,0xf003c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1e,0xf7803c,0x3c01e0,0x1e00f00, 0xf007800,0x7803e00f,0x801e000f,0x80f803e0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x1,0xe0f0000f,0xff00001f,0x8000f87c,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80, 0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x1f,0x800000fe,0xf00780,0x7c0,0x7f001e00,0x3c0007,0xe03f003f,0x3fe0000,0x0,0x3fc00,0x0, 0x7f,0x8001e000,0x781f00f0,0x1e00f003,0xc007e03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3f9f0000,0x7800001e, 0xfe0f078,0x3c1e03c0,0x7807ff,0xff00f000,0x1e07fff8,0xfff8,0xf000,0xf0003c0,0xf81f003,0xc7bc7800,0xfe00000,0x78000003,0xe000003c, 0x1e0,0x1e0,0x0,0x0,0x0,0x1fffc01,0xe000780f,0x1e0,0x780f00,0x1e0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7bf0000,0x1e0000f, 0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xf8000,0x3c000,0x3c003c0,0x1f00f807,0x81f03c00,0x3fe0001e,0xf00000,0x7c00007c, 0xf0,0x3e0,0x3ff801,0x80000000,0x7800000,0x3cfcf800,0x3,0xffff0000,0x0,0x18,0xc0,0x0,0x7c00,0x1fff00,0x700003,0xc00f0003, 0xcfcf8000,0x3e0000f3,0xf3e0079f,0x9f000000,0xf000,0x1000,0x0,0x0,0x0,0x0,0x0,0x1f0,0x1,0xc00f0078,0xf03cfcf,0x800007c0,0x1e000, 0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x8000003c,0xf001,0xf0000000,0x6380000,0xc0000000,0xf81f003,0xfffffe00,0x303, 0x87006000,0x0,0x1ffff,0xfe003ffe,0x7f00,0x0,0x3c003c0,0x3fe1c00,0x3f00000,0x7,0xffc00000,0xf8,0x1f0001ff,0xf0000fff,0x80007ffc, 0xfc000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf001e07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000, 0x7800000,0x3c000001,0xe000fff8,0x3c0f078,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x3fc001e,0x1e03c0f0,0x3c0780, 0x1e03c00,0xf01e000,0x78000780,0x1e0007,0x80f0fc00,0x3fff80,0x1fffc00,0xfffe000,0x7fff0003,0xfff8001f,0xffc0001e,0x3c0f000, 0x1e0003,0xc0f0001e,0x78000f0,0x3c000780,0x780000,0x3c00000,0x1e000000,0xf0001e00,0xf803c00,0x3c078001,0xe03c000f,0x1e00078, 0xf0003c0,0x78001e07,0xfffffe1e,0x1e7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801e00f,0x1e0007,0x807803c0,0x0,0x0,0x0,0x0,0x0, 0x0,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, 0xffc0007e,0xf03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x0,0x3,0xc0001e1f,0x83c0001e,0x3f,0x3e,0xf00780,0x3c0,0x7e001e00, 0x7c000f,0x800f001f,0xffde0000,0x0,0x3e000,0x0,0xf,0x8003e000,0x781e0070,0x1e00f003,0xc001f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f, 0xf81e0007,0x80007800,0x780,0x3f1f0000,0x7800001e,0x7c0f078,0x1e1e03c0,0x7807ff,0xfc00f000,0x1e07fffe,0xffc,0xf000,0xf0003c0, 0x781e003,0xc71c7800,0x1ff00000,0x78000003,0xe000003c,0x1e0,0x1e0,0x0,0x0,0x0,0xffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c, 0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7f000,0x3c000, 0x3c003c0,0xf00f007,0xc1f07c00,0x1fc0001f,0x1f00000,0xfc000ff8,0xf0,0x1ff,0xfffe07,0x80000000,0x7800000,0x7ffcfc00,0x0,0xf000000, 0x0,0x18,0xc0,0x0,0x3e000,0x1ff80,0xe00003,0xc00f0007,0xffcfc000,0x3e0001ff,0xf3f00fff,0x9f800000,0x6000,0x0,0x0,0x7c000, 0x0,0x0,0x0,0xfe,0x0,0xe00f007f,0xff07ffcf,0xc0000fc0,0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00007,0x80000000,0xf800, 0xf0000000,0x6380000,0xc0000000,0x1f03c000,0x1e00,0x303,0x83806000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xfe1c00,0x3f00000,0x0, 0x0,0x3c,0xf801fff,0xfff8,0x7ffc0,0x1f8000,0x3c01e00,0x1e00f000,0xf0078007,0x803c003c,0x1e001e0,0xf003c07,0x8003c000,0x78000, 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0, 0x78000f00,0x1f8001e,0x1e03c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e000f,0x80f0ff00,0x1ffff80,0xffffc00,0x7fffe003, 0xffff001f,0xfff800ff,0xffc007ff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00, 0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x3c7803c,0x3c01e0,0x1e00f00,0xf007800,0x7801f01f, 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, 0x0,0x0,0x0,0x0,0x780000,0x3,0xc0f00000,0xfff003f0,0x1f00f03e,0x7800000,0x3c00,0x1e00,0x1c000,0x7fffff80,0x0,0x7ff80000,0x3, 0xc0001e0f,0x3c0001e,0x7e,0x1f,0x1e00780,0x3e0,0x7e000f00,0x78000f,0x7800f,0xff9e0000,0x0,0x3fc00,0x0,0x7f,0x8003c000,0x781e0070, 0x3e00f803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c00f,0xf81e0007,0x80007800,0x780,0x3e0f8000,0x7800001e,0x7c0f078,0x1e1e03c0, 0x7807ff,0xf000f000,0x1e07807f,0xfe,0xf000,0xf0003c0,0x781e003,0xc71c7800,0x3ef00000,0x78000007,0xc000003c,0x1e0,0x1e0,0x0, 0x0,0x0,0x1ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7ff0000,0x1e0000f,0x3c0f01e, 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x7ff80,0x3c000,0x3c003c0,0xf00f003,0xc1f07800,0x1fc0000f,0x1e00000,0xf8000ff0,0xf0, 0xff,0xffffff,0x80000000,0x3fffc000,0xfff9fe00,0x0,0xf000000,0x0,0x18,0xc0,0x0,0x1f0000,0x1fc0,0x1c00003,0xc00f000f,0xff9fe000, 0x7c0003ff,0xe7f81fff,0x3fc00000,0x0,0x0,0x0,0xfe000,0x1ffffc0f,0xfffffc00,0x0,0xff,0xf0000000,0x700f007f,0xff0fff9f,0xe0000f80, 0x1e000,0x0,0x780001,0xe018001f,0xfff8001c,0xe00fff,0xffc00000,0xf800,0xf0000000,0x6380000,0xc0ffff80,0x3e078000,0x1e00,0x7ff80303, 0x83c06000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000,0x0,0x7f,0xff00001e,0x7c1fff0,0xfff80,0x7ffc00,0x3f0000,0x7c01f00, 0x3e00f801,0xf007c00f,0x803e007c,0x1f003e0,0xf803c07,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 0xe0001e00,0x3c0f03c,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x1f8001e,0x3c03c0f0,0x3c0780,0x1e03c00,0xf01e000, 0x78000780,0x1e001f,0xf07f80,0x3ffff80,0x1ffffc00,0xffffe007,0xffff003f,0xfff801ff,0xffc03fff,0xffc0f000,0x1fffff,0xc0fffffe, 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07, 0xfffffe1e,0x787803c,0x3c01e0,0x1e00f00,0xf007800,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x3ff80fc0,0x7fc1e01f, 0x7800000,0x3c00,0x1e00,0x0,0x7fffff80,0x0,0x7ff80000,0x7,0x80001e00,0x3c0001e,0xfc,0xf,0x1e00780,0x1e0,0x7c000f00,0x78000f, 0x78007,0xff1e0000,0x0,0x3ff00,0x0,0x1ff,0x8003c000,0x781e0070,0x3c007803,0xc000f03c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007, 0x80007800,0x780,0x3c07c000,0x7800001e,0x7c0f078,0xf1e03c0,0x780780,0xf000,0x1e07801f,0x3e,0xf000,0xf0003c0,0x781e003,0xcf1c7800, 0x3cf80000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0,0x0,0x0,0x3ffffc01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007, 0x80003c00,0xf000,0x7ff8000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3fff0,0x3c000,0x3c003c0,0xf81f003, 0xc3b87800,0xf80000f,0x1e00001,0xf0000ff0,0xf0,0xff,0xf03fff,0x80000000,0x3fff8001,0xfff1ff00,0x0,0xf000000,0x0,0x18,0xc0, 0x0,0x380000,0x7c0,0x3c00003,0xc00f001f,0xff1ff000,0xf80007ff,0xc7fc3ffe,0x3fe00000,0x0,0x0,0x0,0x1ff000,0x7ffffe1f,0xffffff00, 0x0,0x7f,0xfe000000,0x780f007f,0xff1fff1f,0xf0001f00,0x1e000,0x0,0x780001,0xe0180000,0xf000001c,0xe00fff,0xffc00000,0x7c00, 0xf0000000,0x31c0001,0x80ffff80,0x3e078000,0x1e00,0x7ff80183,0x81c0c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x3f00000, 0x0,0x7f,0xff00001e,0x7c7ff03,0xc03ff8fe,0x1ffc0f0,0x7e0000,0x7800f00,0x3c007801,0xe003c00f,0x1e0078,0xf003c0,0x7803c07,0x8003c000, 0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c, 0xf0001e0,0x78000f00,0x3fc001e,0x7803c0f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e007f,0xf03fe0,0x7ffff80,0x3ffffc01, 0xffffe00f,0xffff007f,0xfff803ff,0xffc07fff,0xffc0f000,0x1fffff,0xc0fffffe,0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000, 0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e07,0xfffffe1e,0x707803c,0x3c01e0,0x1e00f00,0xf007800, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0x1ff,0xffff8000,0x30f81f00,0xffe1e00f,0x87800000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000, 0x7,0x80001e00,0x3c0001e,0x1f8,0x7,0x83c00780,0x1e0,0x7c000f00,0xf8001e,0x3c001,0xfc1e0000,0x0,0x7fe0,0x0,0xffc,0x3c000,0x781e0070, 0x3ffff803,0xc000783c,0x1e0,0x3c03c0,0x1e00,0x3c000,0x781e0007,0x80007800,0x780,0x3c07c000,0x7800001e,0x380f078,0xf1e03c0, 0x780780,0xf000,0x1e07800f,0x8000001e,0xf000,0xf0003c0,0x3c3c003,0xcf1e7800,0x7c780000,0x7800000f,0x8000003c,0xf0,0x1e0,0x0, 0x0,0x0,0x7f003c01,0xe000780f,0x1e0,0x780fff,0xffe0003c,0x3c000,0xf0078007,0x80003c00,0xf000,0x7f7c000,0x1e0000f,0x3c0f01e, 0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfff8,0x3c000,0x3c003c0,0x781e003,0xc3b87800,0x1fc00007,0x83e00003,0xe0000ff8,0xf0, 0x1ff,0xc007fe,0x0,0x7fff8001,0xffe3ff00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x3c0,0x7800003,0xc00f001f,0xfe3ff000,0xf80007ff, 0x8ffc3ffc,0x7fe00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x1f,0xff000000,0x3c0f007f,0xff1ffe3f,0xf0003e00,0x1e000,0x0,0x780001, 0xe0180000,0xf000001e,0x1e00fff,0xffc00000,0x3f00,0xf0000000,0x31c0001,0x80ffff80,0x1f03c000,0x1e00,0x7ff80183,0x81c0c000, 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x7f,0xff00003c,0xf87f007,0xc03f83ff,0x81fc01f0,0x7c0000,0x7ffff00,0x3ffff801, 0xffffc00f,0xfffe007f,0xfff003ff,0xff807fff,0x8003c000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 0xe0001e00,0x3c0f01e,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0x7fe001e,0xf003c0f0,0x3c0780,0x1e03c00,0xf01e000, 0x78000780,0x1ffffe,0xf00ff0,0xfe00780,0x7f003c03,0xf801e01f,0xc00f00fe,0x7807f0,0x3c0ffff,0xffc0f000,0x1fffff,0xc0fffffe, 0x7fffff0,0x3fffff80,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, 0x1e,0xf07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783e,0x1e0007,0x801e0f80,0x0,0x0,0x0,0x0,0x0,0x0,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,0x1ff,0xffff8000,0x307c0801,0xe1f1e00f,0x87000000, 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x7ff80000,0xf,0x1e00,0x3c0001e,0x3f0,0x7,0x83fffffc,0x1e0,0x7c000f00,0xf0001e,0x3c000,0x3e0000, 0x0,0x1ffc,0x1fffff,0xf0007ff0,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x3c000,0x781e0007,0x80007800, 0x780,0x3c03e000,0x7800001e,0xf078,0x79e03c0,0x780780,0xf000,0x1e078007,0x8000000f,0xf000,0xf0003c0,0x3c3c001,0xee0ef000, 0xf87c0000,0x7800001f,0x3c,0x78,0x1e0,0x0,0x0,0x0,0x7c003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, 0xf000,0x7e3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x1ffc,0x3c000,0x3c003c0,0x781e003,0xe3b8f800, 0x1fc00007,0x83c00007,0xc00000fc,0xf0,0x3e0,0x8001f8,0x0,0x7800000,0xffc7fe00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0, 0xf000003,0xc00f000f,0xfc7fe001,0xf00003ff,0x1ff81ff8,0xffc00000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x3,0xff800000,0x1e0f0078, 0xffc7f,0xe0007c00,0x1e000,0x0,0x780001,0xe0180000,0xf000000e,0x1c00007,0x80000000,0x1f81,0xe0000000,0x38e0003,0x80000000, 0xf81f000,0x1e00,0x7ff801c3,0x80e1c000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf8,0x1f070007,0xc03803ff,0xc1c001f0, 0xf80000,0xfffff00,0x7ffff803,0xffffc01f,0xfffe00ff,0xfff007ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000, 0xf00000,0x7800000,0x3c000001,0xe0001e00,0x780f00f,0x3c078000,0xf03c0007,0x81e0003c,0xf0001e0,0x78000f00,0xf9f001e,0xf003c0f0, 0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1ffffc,0xf003f8,0xf800780,0x7c003c03,0xe001e01f,0xf00f8,0x7807c0,0x3c0fc1e,0xf000, 0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078, 0xf0003c0,0x78001e00,0x1e,0x1e07803c,0x3c01e0,0x1e00f00,0xf007800,0x7800783c,0x1e0007,0x801e0f00,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,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, 0xc071e007,0xcf000000,0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0xf,0xf00,0x780001e,0x7e0,0x7,0x83fffffc,0x1e0,0x7c000f00,0x1f0001e, 0x3c000,0x3c0000,0x0,0x3ff,0x801fffff,0xf003ff80,0x3c000,0x781e0070,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007, 0x80007800,0x780,0x3c01f000,0x7800001e,0xf078,0x79e03c0,0xf00780,0xf000,0x3e078007,0xc000000f,0xf000,0xf0003c0,0x3c3c001, 0xee0ef000,0xf03e0000,0x7800003e,0x3c,0x78,0x1e0,0x0,0x0,0x0,0xf8003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007, 0x80003c00,0xf000,0x7c3e000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0xfc,0x3c000,0x3c003c0,0x3c3e001,0xe7b8f000, 0x3fe00007,0xc7c0000f,0xc000003e,0xf0,0x7c0,0x0,0x0,0x7c00000,0x7fcffc00,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x0,0x1e0,0x1e000003, 0xc00f0007,0xfcffc003,0xe00001ff,0x3ff00ff9,0xff800000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x1f800000,0xf0f0078,0x7fcff, 0xc000fc00,0x1e000,0x0,0x780001,0xe0180000,0xf000000f,0x87c00007,0x80000000,0xfe3,0xe0000000,0x18780c3,0x0,0x7c0f800,0x1e00, 0xc3,0x80e18000,0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x1f0,0x3e00000f,0xc0000303,0xe00003f0,0xf00000,0xfffff80, 0x7ffffc03,0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000, 0x3c000001,0xe0001e00,0x780f00f,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1f0f801f,0xe00780f0,0x3c0780,0x1e03c00, 0xf01e000,0x78000780,0x1ffff8,0xf000f8,0x1f000780,0xf8003c07,0xc001e03e,0xf01f0,0x780f80,0x3c1f01e,0xf000,0x1e0000,0xf00000, 0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00, 0x1e,0x3c07803c,0x3c01e0,0x1e00f00,0xf007800,0x78007c7c,0x1e0007,0x801f1f00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x81c00000,0x303c0003,0x8039e003,0xef000000, 0x3c00,0x1e00,0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0xfc0,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000, 0x0,0x7f,0xe01fffff,0xf00ffc00,0x3c000,0x781f00f0,0x7ffffc03,0xc000781e,0x1e0,0x7803c0,0x1e00,0x1e000,0x781e0007,0x80007800, 0x780,0x3c01f000,0x7800001e,0xf078,0x7de01e0,0xf00780,0x7800,0x3c078003,0xc000000f,0xf000,0xf0003c0,0x3e7c001,0xee0ef001, 0xf01e0000,0x7800003e,0x3c,0x3c,0x1e0,0x0,0x0,0x0,0xf0003c01,0xe000780f,0x1e0,0x780f00,0x3c,0x3c000,0xf0078007,0x80003c00, 0xf000,0x781f000,0x1e0000f,0x3c0f01e,0x1e03c0,0xf00780,0x1e0f000,0x3c003c00,0x3e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0x7df00003, 0xc780000f,0x8000003e,0xf0,0x780,0x0,0x0,0x3c00000,0x3fcff800,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x1f00fc,0x1e0,0x1e000001, 0xe00f0003,0xfcff8003,0xe00000ff,0x3fe007f9,0xff000000,0x0,0x0,0x0,0x1ff000,0x0,0x0,0x0,0x0,0x7c00000,0xf0f0078,0x3fcff,0x8000f800, 0x1e000,0x0,0x780001,0xe0180000,0xf000001f,0xffe00007,0x8000003c,0x7ff,0xc0000000,0x1c3ffc7,0x0,0x3e07c00,0x1e00,0xe3,0x80738000, 0x0,0x78,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0x3e0,0x7c00001d,0xc0000001,0xe0000770,0x1f00000,0xfffff80,0x7ffffc03, 0xffffe01f,0xffff00ff,0xfff807ff,0xffc07fff,0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001, 0xe0001e00,0x780f00f,0x3c03c001,0xe01e000f,0xf00078,0x78003c0,0x3c001e00,0x3e07c01f,0xc00780f0,0x3c0780,0x1e03c00,0xf01e000, 0x78000780,0x1fffc0,0xf0007c,0x1e000780,0xf0003c07,0x8001e03c,0xf01e0,0x780f00,0x3c1e01e,0xf000,0x1e0000,0xf00000,0x7800000, 0x3c000000,0x780000,0x3c00000,0x1e000000,0xf0001e00,0x7803c00,0x3c078001,0xe03c000f,0x1e00078,0xf0003c0,0x78001e00,0x1e,0x7807803c, 0x3c01e0,0x1e00f00,0xf007800,0x78003c78,0x1e0007,0x800f1e00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x83c00000,0x303c0003,0x8039e001,0xee000000,0x1e00,0x3c00, 0x0,0x1e0000,0x0,0x0,0x1e,0xf00,0x780001e,0x1f80,0x7,0x83fffffc,0x1e0,0x3c000f00,0x1e0001e,0x3c000,0x3c0000,0x0,0x1f,0xfc1fffff, 0xf07ff000,0x0,0x780f00f0,0x78003c03,0xc000781e,0x1e0,0xf803c0,0x1e00,0x1e000,0x781e0007,0x80007800,0x780,0x3c00f800,0x7800001e, 0xf078,0x3de01e0,0xf00780,0x7800,0x3c078003,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfe0ff003,0xe01f0000,0x7800007c,0x3c,0x3c, 0x1e0,0x0,0x0,0x0,0xf0007c01,0xe000f80f,0x800001e0,0xf80f00,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x780f800,0x1e0000f, 0x3c0f01e,0x1e03c0,0x1f00780,0x3e0f000,0x7c003c00,0x1e,0x3c000,0x3c003c0,0x3c3c001,0xe71cf000,0xf8f80003,0xe780001f,0x1e, 0xf0,0x780,0x0,0x0,0x3c00000,0x1ffff000,0x0,0x1e000000,0x0,0x18,0xc0,0x0,0x3bc1de,0x1e0,0xf000001,0xe00f0001,0xffff0007,0xc000007f, 0xffc003ff,0xfe000000,0x0,0x0,0x0,0xfe000,0x0,0x0,0x0,0x0,0x3c00000,0x1e0f0078,0x1ffff,0x1f000,0x1e000,0x0,0x780000,0xf0180000, 0xf000001f,0xfff00007,0x8000003c,0x1ff,0x80000000,0xe0ff0e,0x0,0x1f03e00,0x1e00,0x70,0x70000,0x0,0x78,0x0,0x0,0x0,0x3c003c0, 0xe1c00,0x0,0x0,0x0,0x7c0,0xf8000019,0xc0000000,0xe0000670,0x1e00000,0xf000780,0x78003c03,0xc001e01e,0xf00f0,0x780780,0x3c0f807, 0x8001e000,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf80f007,0xbc03c001,0xe01e000f, 0xf00078,0x78003c0,0x3c001e00,0x7c03e00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80, 0xf0007c07,0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0xf800,0x1e0000,0xf00000,0x7800000,0x3c000000,0x780000,0x3c00000,0x1e000000, 0xf0001e00,0x7803c00,0x3c078003,0xe03c001f,0x1e000f8,0xf0007c0,0x78003e00,0x1f8001f,0xf00f803c,0x3c01e0,0x1e00f00,0xf007800, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf,0x3c00000,0x303c0003,0x8039f001,0xfe000000,0x1e00,0x3c00,0x0,0x1e0000,0x0,0x0,0x3c,0xf00, 0x780001e,0x3f00,0x7,0x80000780,0x3e0,0x3e000f00,0x3c0001e,0x3c000,0x7c0000,0x0,0x3,0xfe000000,0xff8000,0x0,0x3c0f81f0,0xf0001e03, 0xc000780f,0x1e0,0xf003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x780,0x3c007c00,0x7800001e,0xf078,0x3de01e0,0xf00780,0x7800, 0x3c078001,0xe000000f,0xf000,0xf0003c0,0x1e78001,0xfc07f003,0xe00f0000,0x78000078,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, 0xf000f007,0x800000f0,0xf80780,0x3c,0x1e001,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78001,0xe71df000,0xf8f80001,0xef80003e,0x1e,0xf0,0x780,0x0,0x0,0x3c00000, 0xfffe000,0x0,0x3e000000,0x0,0x18,0x7fff,0xc0000000,0x60c306,0x1e0,0x7800001,0xe00f0000,0xfffe0007,0x8000003f,0xff8001ff, 0xfc000000,0x0,0x0,0x0,0x7c000,0x0,0x0,0x0,0x0,0x3c00000,0x3c0f0078,0xfffe,0x3e000,0x1e000,0x0,0x780000,0xf0180000,0xf000003c, 0xfcf80007,0x8000003c,0x7f,0x0,0x70001c,0x0,0xf81f00,0x0,0x38,0xe0000,0x0,0x0,0x0,0x0,0x0,0x3c003c0,0xe1c00,0x0,0x0,0x0,0xf81, 0xf0000039,0xc0000000,0xe0000e70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007,0x8000f000,0x78000, 0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0xf00f007,0xbc03c001,0xe01e000f,0xf00078,0x78003c0, 0x3c001e00,0xf801f00f,0x800780f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07,0x8003e03c, 0x1f01e0,0xf80f00,0x7c1e01e,0x7800,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00,0xf003c00, 0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xe00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef8,0x1f000f, 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, 0x0,0x0,0xf,0x3c00000,0x307c0003,0x8038f000,0xfc000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e00003c,0x780,0xf00001e, 0x7e00,0xf,0x80000780,0x3c0,0x3e001e00,0x3c0001f,0x7c000,0x780007,0xe000003f,0x0,0xfe000000,0xfe0000,0x0,0x3c07c3f0,0xf0001e03, 0xc000f80f,0x800001e0,0x1f003c0,0x1e00,0xf000,0x781e0007,0x80007800,0x4000f80,0x3c003c00,0x7800001e,0xf078,0x1fe01f0,0x1f00780, 0x7c00,0x7c078001,0xf000001f,0xf000,0xf0003c0,0x1e78001,0xfc07f007,0xc00f8000,0x780000f8,0x3c,0x1e,0x1e0,0x0,0x0,0x0,0xf0007c01, 0xf000f007,0xc00000f0,0xf80780,0x3c,0x1f003,0xf0078007,0x80003c00,0xf000,0x7807c00,0x1e0000f,0x3c0f01e,0x1e01e0,0x1e007c0, 0x3c07800,0x7c003c00,0x1e,0x3c000,0x3c007c0,0x1e78000,0xfe0fe001,0xf07c0001,0xef00007c,0x1e,0xf0,0x780,0x0,0x0,0x1e00000, 0x7cfc000,0xfc00000,0x3c00000f,0xc3f00000,0x18,0x7fff,0xc0000000,0x406303,0x3e0,0x3c00001,0xf00f0000,0x7cfc000f,0x8000001f, 0x3f0000f9,0xf8000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x780700f8,0x7cfc,0x7c000,0x1e000,0x0,0x780000,0xf8180000, 0xf0000070,0x3c0007,0x8000003c,0x3f,0x80000000,0x3c0078,0x0,0x780f00,0x0,0x1e,0x3c0000,0x0,0x0,0x0,0x0,0x0,0x3e007c0,0xe1c00, 0x0,0x0,0x0,0xf01,0xe0000071,0xc0000000,0xe0001c70,0x1e00000,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, 0x8000f800,0x78000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x1f00f003,0xfc03e003,0xe01f001f, 0xf800f8,0x7c007c0,0x3e003e01,0xf000f80f,0xf00f0,0x3c0780,0x1e03c00,0xf01e000,0x78000780,0x1e0000,0xf0003c,0x1e000f80,0xf0007c07, 0x8003e03c,0x1f01e0,0xf80f00,0x7c1e01e,0x7c00,0xf0000,0x780000,0x3c00000,0x1e000000,0x780000,0x3c00000,0x1e000000,0xf0000f00, 0xf003c00,0x3c03c003,0xc01e001e,0xf000f0,0x7800780,0x3c003c00,0x1f8000f,0xc00f003c,0x7c01e0,0x3e00f00,0x1f007800,0xf8001ef0, 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, 0x0,0x0,0x0,0x0,0x780000,0xf,0x3800040,0x30780003,0x8038f800,0x78000000,0x1e00,0x3c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, 0x780,0x1f00001e,0xfc00,0x20001f,0x780,0x80007c0,0x1f001e00,0x7c0000f,0x78000,0xf80007,0xe000003f,0x0,0x1e000000,0xf00000, 0x3c000,0x3c03fff0,0xf0001e03,0xc001f007,0x800101e0,0x7e003c0,0x1e00,0x7800,0x781e0007,0x80007800,0x6000f00,0x3c003e00,0x7800001e, 0xf078,0x1fe00f0,0x1e00780,0x3c00,0x78078000,0xf020001e,0xf000,0x7800780,0xff0001,0xfc07f00f,0x8007c000,0x780001f0,0x3c,0xf, 0x1e0,0x0,0x0,0x0,0xf800fc01,0xf801f007,0xc00100f8,0x1f807c0,0x40003c,0xf807,0xf0078007,0x80003c00,0xf000,0x7803e00,0x1f0000f, 0x3c0f01e,0x1e01f0,0x3e007e0,0x7c07c00,0xfc003c00,0x1e,0x3e000,0x3e007c0,0x1ff8000,0xfe0fe003,0xe03e0001,0xff0000fc,0x1e, 0xf0,0x780,0x0,0x0,0x1f00080,0x3cf8000,0xfc00000,0x3c00001f,0x83f00000,0x18,0xc0,0x0,0xc06203,0x40003c0,0x1c00000,0xf80f0000, 0x3cf8001f,0xf,0x3e000079,0xf0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x700780fc,0x3cf8,0xfc000,0x1e000,0x0,0x780000, 0x7c180000,0xf0000020,0x100007,0x8000003c,0xf,0x80000000,0x1f01f0,0x0,0x380700,0x0,0xf,0x80f80000,0x0,0x0,0x0,0x0,0x0,0x3e007c0, 0xe1c00,0x0,0x0,0x0,0xe01,0xc0000071,0xc0000001,0xc0001c70,0x1e00040,0x1e0003c0,0xf0001e07,0x8000f03c,0x781e0,0x3c0f00,0x1e0f007, 0x80007800,0x10078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e00,0x7e00f003,0xfc01e003,0xc00f001e, 0x7800f0,0x3c00780,0x1e003c00,0xe000700f,0x800f0078,0x7803c0,0x3c01e00,0x1e00f000,0xf0000780,0x1e0000,0xf0003c,0x1f001f80, 0xf800fc07,0xc007e03e,0x3f01f0,0x1f80f80,0xfc1e01f,0x7c00,0x100f8000,0x807c0004,0x3e00020,0x1f000100,0x780000,0x3c00000,0x1e000000, 0xf0000f80,0x1f003c00,0x3c03e007,0xc01f003e,0xf801f0,0x7c00f80,0x3e007c00,0x1f8000f,0x801f003e,0x7c01f0,0x3e00f80,0x1f007c00, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x780000,0xf,0x7800078,0x31f80001,0xc070fc00,0xfc000000,0x1e00,0x7c00,0x0,0x1e0000,0xfc0000,0x0,0x7e000078, 0x7c0,0x1f00001e,0x1f000,0x38003f,0x780,0xe000f80,0x1f803e00,0x780000f,0x800f8000,0x1f00007,0xe000003f,0x0,0x2000000,0x800000, 0x3c000,0x3e01ff71,0xf0001f03,0xc007f007,0xc00301e0,0x1fc003c0,0x1e00,0x7c00,0x781e0007,0x80007800,0x7801f00,0x3c001f00,0x7800001e, 0xf078,0xfe00f8,0x3e00780,0x3e00,0xf8078000,0xf838003e,0xf000,0x7c00f80,0xff0000,0xfc07e00f,0x8003c000,0x780001e0,0x3c,0xf, 0x1e0,0x0,0x0,0x0,0xf801fc01,0xfc03e003,0xe003007c,0x3f803e0,0x1c0003c,0xfc0f,0xf0078007,0x80003c00,0xf000,0x7801f00,0xf8000f, 0x3c0f01e,0x1e00f8,0x7c007f0,0xf803e01,0xfc003c00,0x8003e,0x1f000,0x1e00fc0,0xff0000,0xfe0fe007,0xc01f0000,0xfe0000f8,0x1e, 0xf0,0x780,0x0,0x0,0xf80180,0x1cf0000,0x1f800000,0x3c00001f,0x83e00000,0x18,0xc0,0x0,0xc06203,0x70007c0,0xe00000,0x7e0f0000, 0x1cf0001e,0x7,0x3c000039,0xe0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x7c00000,0xe00780fc,0x2001cf0,0xf8000,0x1e000,0x0, 0x780000,0x7e182000,0xf0000000,0x7,0x8000003c,0x7,0xc0000000,0x7ffc0,0x0,0x180300,0x0,0x3,0xffe00000,0x0,0x0,0x0,0x0,0x0, 0x3f00fc0,0xe1c00,0x0,0x0,0x0,0xc01,0x800000e1,0xc0000003,0xc0003870,0x1f001c0,0x3e0003e1,0xf0001f0f,0x8000f87c,0x7c3e0,0x3e1f00, 0x1f1e007,0x80007c00,0x30078000,0x3c0000,0x1e00000,0xf000000,0xf00000,0x7800000,0x3c000001,0xe0001e03,0xfc00f001,0xfc01f007, 0xc00f803e,0x7c01f0,0x3e00f80,0x1f007c00,0x4000201f,0xc01f007c,0xf803e0,0x7c01f00,0x3e00f801,0xf0000780,0x1e0000,0xf0007c, 0x1f003f80,0xf801fc07,0xc00fe03e,0x7f01f0,0x3f80f80,0x1fc1f03f,0x803e00,0x3007c003,0x803e001c,0x1f000e0,0xf800700,0x780000, 0x3c00000,0x1e000000,0xf00007c0,0x3e003c00,0x3c01f00f,0x800f807c,0x7c03e0,0x3e01f00,0x1f00f800,0x1f80007,0xc03e001e,0xfc00f0, 0x7e00780,0x3f003c01,0xf8000fe0,0x1fc03e,0x3f800,0x0,0x0,0x0,0x0,0x0,0x0,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,0xfff00001,0xe0f07f03,0xfe000000,0xf00,0x7800,0x0, 0x1e0000,0xfc0000,0x0,0x7e0000f0,0x3f0,0x7e000fff,0xfc03ffff,0xf83f00fe,0x780,0xfc03f80,0xfc0fc00,0xf800007,0xe03f0018,0x7e00007, 0xe000003f,0x0,0x0,0x0,0x3c000,0x1e007c71,0xe0000f03,0xffffe003,0xf01f01ff,0xff8003ff,0xffe01e00,0x3f01,0xf81e0007,0x803ffff0, 0x7e03f00,0x3c000f00,0x7ffffe1e,0xf078,0xfe007e,0xfc00780,0x1f83,0xf0078000,0x783f00fe,0xf000,0x3f03f00,0xff0000,0xfc07e01f, 0x3e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7e07fc01,0xfe07e001,0xf80f007e,0x7f801f8,0xfc0003c,0x7ffe,0xf0078007, 0x807ffffe,0xf000,0x7801f00,0xfff00f,0x3c0f01e,0x1e00fc,0xfc007f8,0x1f803f03,0xfc003c00,0xf80fc,0x1fff0,0x1f83fc0,0xff0000, 0xfc07e007,0xc01f0000,0xfe0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfe0780,0xfe0000,0x1f000000,0x3c00001f,0x7c00e03,0x81c00018, 0xc0,0x0,0x406203,0x7e01fc0,0x700000,0x7fffff80,0xfe0003f,0xffffc003,0xf800001f,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1f0, 0x1f800001,0xc007c1fe,0x6000fe0,0x1ffffe,0x1e000,0x0,0x780000,0x3f98e03f,0xffff8000,0x7,0x8000003c,0x7,0xc0000000,0xfe00, 0x0,0x80100,0x0,0x0,0x7f000000,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3f83fe8,0xe1c00,0x0,0x0,0x0,0x801,0xc1,0xc0000007,0x80003070, 0xfc0fc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc03f01,0xf007ffff,0xc03ffffe,0x1fffff0,0xfffff80,0x7fffe003, 0xffff001f,0xfff800ff,0xffc01fff,0xf800f001,0xfc00fc1f,0x8007e0fc,0x3f07e0,0x1f83f00,0xfc1f800,0x1f,0xf07e003f,0x3f001f8, 0x1f800fc0,0xfc007e07,0xe0000780,0x1e0000,0xf301f8,0xfc0ff80,0x7e07fc03,0xf03fe01f,0x81ff00fc,0xff807e0,0x7fc0f87f,0x81801f80, 0xf003f01f,0x801f80fc,0xfc07e0,0x7e03f00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff807e0,0x7e003c00,0x3c01f81f,0x800fc0fc,0x7e07e0, 0x3f03f00,0x1f81f800,0x1f8000f,0xe07e001f,0x83fc00fc,0x1fe007e0,0xff003f07,0xf8000fe0,0x1fe07e,0x3f800,0x0,0x0,0x0,0x0,0x0, 0x0,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, 0xffe00000,0xffe03fff,0xdf000000,0xf00,0x7800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0x1ff,0xfc000fff,0xfc03ffff,0xf83ffffc,0x780, 0xfffff00,0x7fff800,0xf000007,0xffff001f,0xffe00007,0xe000003f,0x0,0x0,0x0,0x3c000,0x1e000001,0xe0000f03,0xffffc001,0xffff01ff, 0xff0003ff,0xffe01e00,0x1fff,0xf81e0007,0x803ffff0,0x7fffe00,0x3c000f80,0x7ffffe1e,0xf078,0xfe003f,0xff800780,0xfff,0xf0078000, 0x7c3ffffc,0xf000,0x3ffff00,0xff0000,0xf803e01e,0x1e000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x7fffbc01,0xffffc000, 0xffff003f,0xfff800ff,0xffc0003c,0x3ffe,0xf0078007,0x807ffffe,0xf000,0x7800f80,0x7ff00f,0x3c0f01e,0x1e007f,0xff8007ff,0xff001fff, 0xbc003c00,0xffffc,0x1fff0,0x1fffbc0,0xff0000,0x7c07c00f,0x800f8000,0x7e0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x7fff80,0x7c0000, 0x1f000000,0x3c00001e,0x7c00f07,0xc1e00018,0xc0,0x0,0x60e303,0x7ffff80,0x380000,0x3fffff80,0x7c0003f,0xffffc001,0xf000000f, 0x80000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff800003,0x8003ffff,0xfe0007c0,0x1ffffe,0x1e000,0x0,0x780000,0x1fffe03f,0xffff8000, 0x7,0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3fffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x1c1, 0xc000000f,0x7070,0x7fffc0,0x3c0001e1,0xe0000f0f,0x7878,0x3c3c0,0x1e1e00,0xf1e007,0xffc01fff,0xf007ffff,0xc03ffffe,0x1fffff0, 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xf000f001,0xfc007fff,0x3fff8,0x1fffc0,0xfffe00,0x7fff000,0x3b,0xfffc003f, 0xfff001ff,0xff800fff,0xfc007fff,0xe0000780,0x1e0000,0xf3fff8,0xffff780,0x7fffbc03,0xfffde01f,0xffef00ff,0xff7807ff,0xfbc0ffff, 0xff800fff,0xf001ffff,0x800ffffc,0x7fffe0,0x3ffff00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff803ff,0xfc003c00,0x3c00ffff,0x7fff8, 0x3fffc0,0x1fffe00,0xffff000,0x1f,0xfffc001f,0xffbc00ff,0xfde007ff,0xef003fff,0x780007e0,0x1ffffc,0x1f800,0x0,0x0,0x0,0x0, 0x0,0x0,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, 0xffc00000,0x7fc01fff,0x9f800000,0xf80,0xf800,0x0,0x0,0xfc0000,0x0,0x7e0000f0,0xff,0xf8000fff,0xfc03ffff,0xf83ffff8,0x780, 0xffffe00,0x7fff000,0xf000003,0xfffe001f,0xffc00007,0xe000003f,0x0,0x0,0x0,0x3c000,0xf000003,0xe0000f83,0xffff0000,0xffff01ff, 0xfc0003ff,0xffe01e00,0xfff,0xf01e0007,0x803ffff0,0x7fffc00,0x3c0007c0,0x7ffffe1e,0xf078,0x7e003f,0xff000780,0x7ff,0xe0078000, 0x3c3ffff8,0xf000,0x1fffe00,0x7e0000,0xf803e03e,0x1f000,0x780003ff,0xfffc003c,0x7,0x800001e0,0x0,0x0,0x0,0x3fff3c01,0xefff8000, 0x7ffe001f,0xff78007f,0xff80003c,0x1ffc,0xf0078007,0x807ffffe,0xf000,0x78007c0,0x3ff00f,0x3c0f01e,0x1e003f,0xff0007bf,0xfe000fff, 0xbc003c00,0xffff8,0xfff0,0xfff3c0,0x7e0000,0x7c07c01f,0x7c000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0x3fff80,0x380000, 0x3e000000,0x7c00003e,0x7801f07,0xc1e00018,0xc0,0x0,0x39c1ce,0x7ffff00,0x1c0000,0xfffff80,0x380003f,0xffffc000,0xe0000007, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ff,0xff000007,0x1ffcf,0xfe000380,0x1ffffe,0x1e000,0x0,0x780000,0xfffe03f,0xffff8000,0x7, 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dffdf8,0xe1c00,0x0,0x0,0x0,0x0,0x381, 0xc000001e,0xe070,0x7fff80,0x7c0001f3,0xe0000f9f,0x7cf8,0x3e7c0,0x1f3e00,0xfbe007,0xffc00fff,0xf007ffff,0xc03ffffe,0x1fffff0, 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01fff,0xc000f000,0xfc007ffe,0x3fff0,0x1fff80,0xfffc00,0x7ffe000,0x79,0xfff8001f, 0xffe000ff,0xff0007ff,0xf8003fff,0xc0000780,0x1e0000,0xf3fff0,0x7ffe780,0x3fff3c01,0xfff9e00f,0xffcf007f,0xfe7803ff,0xf3c07ff3, 0xff8007ff,0xe000ffff,0x7fff8,0x3fffc0,0x1fffe00,0xfffffc07,0xffffe03f,0xffff01ff,0xfff801ff,0xf8003c00,0x3c007ffe,0x3fff0, 0x1fff80,0xfffc00,0x7ffe000,0x1d,0xfff8000f,0xff3c007f,0xf9e003ff,0xcf001ffe,0x780007c0,0x1efff8,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,0x0,0x0,0x0,0x0,0x780000,0x1e,0xf000003, 0xfe000000,0x1f000fff,0xfc00000,0x780,0xf000,0x0,0x0,0xf80000,0x0,0x7e0001e0,0x7f,0xf0000fff,0xfc03ffff,0xf81ffff0,0x780, 0x7fff800,0x1ffe000,0x1f000000,0xfff8001f,0xff000007,0xe000003e,0x0,0x0,0x0,0x3c000,0xf800003,0xc0000783,0xfff80000,0x3ffe01ff, 0xe00003ff,0xffe01e00,0x7ff,0xc01e0007,0x803ffff0,0x3fff800,0x3c0003c0,0x7ffffe1e,0xf078,0x7e000f,0xfe000780,0x3ff,0xc0078000, 0x3e1fffe0,0xf000,0x7ff800,0x7e0000,0xf803e07c,0xf800,0x780003ff,0xfffc003c,0x3,0xc00001e0,0x0,0x0,0x0,0xffe3c01,0xe7ff0000, 0x3ffc000f,0xfe78003f,0xfe00003c,0x7f0,0xf0078007,0x807ffffe,0xf000,0x78003e0,0xff00f,0x3c0f01e,0x1e001f,0xfe00079f,0xfc0007ff, 0x3c003c00,0x7ffe0,0x1ff0,0x7fe3c0,0x7e0000,0x7c07c03e,0x3e000,0x7c0001ff,0xffe0001e,0xf0,0x780,0x0,0x0,0xfff00,0x100000, 0x3e000000,0x7800003c,0xf800f07,0xc1e00018,0xc0,0x0,0x1f80fc,0x3fffc00,0xc0000,0x3ffff80,0x100003f,0xffffc000,0x40000002, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xfc000006,0xff87,0xfc000100,0x1ffffe,0x1e000,0x0,0x780000,0x3ffc03f,0xffff8000,0x7, 0x8000003c,0x3,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1ffff,0xfe000000,0x0,0x0,0x3dff9f8,0xe1c00,0x0,0x0,0x0,0x0,0x3ff, 0xf800003c,0xfffe,0x1ffe00,0x780000f3,0xc000079e,0x3cf0,0x1e780,0xf3c00,0x7bc007,0xffc003ff,0xe007ffff,0xc03ffffe,0x1fffff0, 0xfffff80,0x7fffe003,0xffff001f,0xfff800ff,0xffc01ffc,0xf000,0xfc001ffc,0xffe0,0x7ff00,0x3ff800,0x1ffc000,0x70,0xfff00007, 0xff80003f,0xfc0001ff,0xe0000fff,0x780,0x1e0000,0xf3ffe0,0x1ffc780,0xffe3c00,0x7ff1e003,0xff8f001f,0xfc7800ff,0xe3c03fe1, 0xff0003ff,0xc0007ffc,0x3ffe0,0x1fff00,0xfff800,0xfffffc07,0xffffe03f,0xffff01ff,0xfff800ff,0xf0003c00,0x3c003ffc,0x1ffe0, 0xfff00,0x7ff800,0x3ffc000,0x38,0xfff00007,0xfe3c003f,0xf1e001ff,0x8f000ffc,0x780007c0,0x1e7ff0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x30000000, 0x1fc,0x0,0x780,0xf000,0x0,0x0,0x1f80000,0x0,0x1e0,0x1f,0xc0000000,0x0,0x1ff80,0x0,0xffc000,0x7f8000,0x0,0x3fe00007,0xfc000000, 0x7e,0x0,0x0,0x0,0x0,0x7c00000,0x0,0x0,0xff00000,0x0,0x0,0xfe,0x0,0x0,0x3fc000,0x0,0x0,0x0,0x3,0xf8000000,0xff,0xc0000000, 0x1ff00,0x0,0x1fe000,0x0,0x0,0x0,0x0,0x3c,0x3,0xc00001e0,0x0,0x0,0x0,0x3f80000,0x1fc0000,0x7f00003,0xf8000007,0xf0000000, 0x0,0xf0000000,0x0,0xf000,0x0,0x0,0x0,0x7,0xf8000787,0xf00001fc,0x3c000000,0x7f80,0x0,0x1f8000,0x0,0x0,0x0,0x7c000000,0x1e, 0xf0,0x780,0x0,0x0,0x3fc00,0x0,0x3c000000,0x7800003c,0xf000601,0xc00018,0xc0,0x0,0x0,0x3fe000,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0xf,0xf0000000,0x7e03,0xf0000000,0x0,0x0,0x0,0x0,0xfe0000,0x0,0x0,0x3c,0x2007,0x80000000,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c7e0f0,0xe1c00,0x0,0x3800000,0x0,0x0,0x3ff,0xf8000078,0xfffe,0x7f800,0x0,0x0,0x0,0x0, 0x0,0x0,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7f0,0x3f80,0x1fc00,0xfe000,0x7f0000,0x70,0x3fc00001,0xfe00000f,0xf000007f, 0x800003fc,0x0,0x0,0xff00,0x7f0000,0x3f80000,0x1fc00000,0xfe000007,0xf000003f,0x80001f80,0xfc00007f,0xfe0,0x7f00,0x3f800, 0x1fc000,0x0,0x0,0x0,0x3f,0xc0000000,0xff0,0x7f80,0x3fc00,0x1fe000,0xff0000,0x78,0x3fc00001,0xf800000f,0xc000007e,0x3f0,0x7c0, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x78000000,0x1e,0xf0,0x780,0x0,0x0,0x0,0x0,0x3c000000,0x78000078,0xf000000,0x18,0xc0,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,0x0,0x0,0x3c,0x3c0f,0x80000000, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0x1800000,0x0,0x0,0x3ff,0xf80000f0,0xfffe,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,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,0x3c0,0x1e000,0x0,0x0,0x1f00000,0x0,0x3c0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7c,0x0,0x0,0x0,0x0,0x1f80000, 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, 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, 0x1f,0xf0,0xf80,0x0,0x0,0x0,0x0,0x78000000,0xf8000078,0x1e000000,0x8,0x40,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,0x0,0x0,0x3c,0x3fff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 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, 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, 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, 0x0,0xf000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x0,0xf0000000,0x1f,0x800000f0,0x1f80,0x0,0x0,0x0,0x0, 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, 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, 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, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3f,0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4003,0xe0000000,0x0,0x1f000,0x0,0x0, 0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x1,0xf0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0x70000001,0xf00000e0, 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, 0x0,0x0,0x3c,0xff8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0xe1c00,0x0,0xe00000,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,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,0x0,0x0,0x0,0x1f00,0x1e0000, 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, 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, 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, 0xf0000000,0x7fe0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x780f,0xc0000000,0x0,0x3e000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, 0x0,0x0,0x0,0x0,0x3,0xe0000000,0xf,0xfc0000f0,0x3ff00,0x0,0x0,0x0,0x0,0xf0000103,0xe0000000,0x0,0x0,0x0,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,0x0,0x0,0x3c,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c00000,0x0,0x0,0x21e00000,0x0,0x0,0x1,0xc00003ff,0xe0000070,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10f, 0x0,0x0,0x0,0x0,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, 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, 0x0,0x0,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, 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, 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, 0x0,0x0,0x7fff,0xc0000000,0x0,0x3ffe000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0xe0000000,0x7,0xfc0000f0, 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, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x1fffffe0,0x0,0x0,0x0,0x0,0x0,0x0,0x7fff,0x80000000,0x0,0x3ffc000,0x0,0x0,0x0,0x0,0x780,0x0,0x3c000000,0x0, 0x0,0x0,0x0,0x0,0x7f,0xc0000000,0x0,0xfc0000f0,0x3f000,0x0,0x0,0x0,0x0,0x1ff,0xc0000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x780,0x0,0x3c000000,0x0,0x0,0x0,0x0,0x0,0x7f,0x80000000,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1ff,0x80000000,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x3f800000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1fc,0x0, 0x0,0x0,0x0,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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 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, 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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,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, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0 }; // Definition of a 40x38 'danger' color logo const unsigned char logo40x38[4576] = { 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 200,200,200,91,49,124,118,124,71,32,124,95,49,56,114,52,82,121,0}; // Display a warning message if parameter 'cond' is true. inline void warn(const bool cond, const char *format,...) { if (cimg::exception_mode()>=1 && cond) { std::va_list ap; va_start(ap,format); std::fprintf(stderr,"\n "); std::vfprintf(stderr,format,ap); std::fputc('\n',stderr); va_end(ap); } } inline int xln(const int x) { return x>0?(int)(1+std::log10((double)x)):1; } inline char uncase(const char x) { return (char)((x<'A'||x>'Z')?x:x-'A'+'a'); } inline float atof(const char *str) { float x=0,y=1; if (!str) return 0; else { std::sscanf(str,"%g/%g",&x,&y); return x/y; } } inline int strlen(const char *s) { if (s) { int k; for (k=0; s[k]; k++) ; return k; } return -1; } inline int strncmp(const char *s1,const char *s2,const int l) { if (s1 && s2) { int n=0; for (int k=0; k=0 && s[l]!=c; l--) ; return l; } return -1; } inline const char* basename(const char *s) { return (cimg_OS!=2)?(s?s+1+cimg::strfind(s,'/'):0):(s?s+1+cimg::strfind(s,'\\'):0); } inline void system(const char *command, const char *module_name=0) { #if cimg_OS==2 PROCESS_INFORMATION pi; STARTUPINFO si; std::memset(&pi, 0, sizeof(PROCESS_INFORMATION)); std::memset(&si, 0, sizeof(STARTUPINFO)); GetStartupInfo(&si); si.cb = sizeof(si); si.wShowWindow = SW_HIDE; si.dwFlags |= SW_HIDE; const BOOL res = CreateProcess((LPCTSTR)module_name,(LPTSTR)command,0,0,FALSE,0,0,0,&si,&pi); if (res) { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else #endif std::system(command); command=module_name=0; } // Convert filename into windows-style (without spaces) #if cimg_OS==2 inline void winformat_string(char *const s) { if (s && s[0]) { char *const ns = new char[MAX_PATH]; GetShortPathNameA(s,ns,MAX_PATH); std::strcpy(s,ns); } } #else inline void winformat_string(char *const) {} #endif // Return path to the "Program files/" directory (windows only). /** This function is used internally in imagemagick_path, graphicsmagick_path and medcon_path on Windows platforms **/ #if cimg_OS==2 inline const char* programfiles_path() { static char *st_programfiles_path = 0; if (!st_programfiles_path) { st_programfiles_path = new char[MAX_PATH]; // Note : in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). if (!SHGetSpecialFolderPathA(0,st_programfiles_path,0x0026,false)) { const char *pfPath = getenv("PROGRAMFILES"); if (pfPath) std::strcpy(st_programfiles_path,pfPath); else std::strcpy(st_programfiles_path,"C:\\PROGRA~1"); } } return st_programfiles_path; } #endif //! Return path of the ImageMagick's \c convert tool. /** If you have installed the ImageMagick package in a standard directory, this function should return the correct path of the \c convert tool used by the %CImg Library to load and save compressed image formats. Conversely, if the \c convert executable is not auto-detected by the function, you can define the macro \c cimg_imagemagick_path with the correct path of the \c convert executable, before including CImg.h in your program : \code #define cimg_imagemagick_path "/users/thatsme/local/bin/convert" #include "CImg.h" int main() { CImg<> img("my_image.jpg"); // Read a JPEG image file. return 0; } \endcode Note that non compressed image formats can be read without installing ImageMagick. \sa temporary_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick(). **/ inline const char* imagemagick_path() { static char *st_imagemagick_path = 0; if (!st_imagemagick_path) { st_imagemagick_path = new char[1024]; bool path_found = false; std::FILE *file = 0; #ifdef cimg_imagemagick_path std::strcpy(st_imagemagick_path,cimg_imagemagick_path); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } #endif #if cimg_OS==2 const char *pf_path = programfiles_path(); if (!path_found) { std::sprintf(st_imagemagick_path,".\\convert.exe"); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } } { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u-Q\\convert.exe",pf_path,k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u\\convert.exe",pf_path,k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",pf_path,k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"%s\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",pf_path,k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u-Q\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"C:\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u-Q\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u-Q\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_imagemagick_path,"D:\\IMAGEM~1.%u\\VISUA~1\\BIN\\convert.exe",k); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} if (!path_found) std::strcpy(st_imagemagick_path,"convert.exe"); #else if (!path_found) { std::sprintf(st_imagemagick_path,"./convert"); if ((file=std::fopen(st_imagemagick_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) std::strcpy(st_imagemagick_path,"convert"); #endif winformat_string(st_imagemagick_path); } return st_imagemagick_path; } //! Return path of the GraphicsMagick's \c gm tool. /** If you have installed the GraphicsMagick package in a standard directory, this function should return the correct path of the \c gm tool used by the %CImg Library to load and save compressed image formats. Conversely, if the \c gm executable is not auto-detected by the function, you can define the macro \c cimg_graphicsmagick_path with the correct path of the \c gm executable, before including CImg.h in your program : \code #define cimg_graphicsmagick_path "/users/thatsme/local/bin/gm" #include "CImg.h" int main() { CImg<> img("my_image.jpg"); // Read a JPEG image file. return 0; } \endcode Note that non compressed image formats can be read without installing ImageMagick. \sa temporary_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick(). **/ inline const char* graphicsmagick_path() { static char *st_graphicsmagick_path = 0; if (!st_graphicsmagick_path) { st_graphicsmagick_path = new char[1024]; bool path_found = false; std::FILE *file = 0; #ifdef cimg_graphicsmagick_path std::strcpy(st_graphicsmagick_path,cimg_graphicsmagick_path); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } #endif #if cimg_OS==2 const char* pf_path = programfiles_path(); if (!path_found) { std::sprintf(st_graphicsmagick_path,".\\gm.exe"); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } } { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u-Q\\gm.exe",pf_path,k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u\\gm.exe",pf_path,k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"%s\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",pf_path,k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u-Q\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"C:\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u-Q\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u-Q\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} { for (unsigned int k=0; k<=9 && !path_found; k++) { std::sprintf(st_graphicsmagick_path,"D:\\GRAPHI~1.%u\\VISUA~1\\BIN\\gm.exe",k); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } }} if (!path_found) std::strcpy(st_graphicsmagick_path,"gm.exe"); #else if (!path_found) { std::sprintf(st_graphicsmagick_path,"./gm"); if ((file=std::fopen(st_graphicsmagick_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) std::strcpy(st_graphicsmagick_path,"gm"); #endif winformat_string(st_graphicsmagick_path); } return st_graphicsmagick_path; } //! Return path of the \c XMedcon tool. /** If you have installed the XMedcon package in a standard directory, this function should return the correct path of the \c medcon tool used by the %CIg Library to load DICOM image formats. Conversely, if the \c medcon executable is not auto-detected by the function, you can define the macro \c cimg_medcon_path with the correct path of the \c medcon executable, before including CImg.h in your program : \code #define cimg_medcon_path "/users/thatsme/local/bin/medcon" #include "CImg.h" int main() { CImg<> img("my_image.dcm"); // Read a DICOM image file. return 0; } \endcode Note that \c medcon is only needed if you want to read DICOM image formats. \sa temporary_path(), get_load_dicom(), load_dicom(). **/ inline const char* medcon_path() { static char *st_medcon_path = 0; if (!st_medcon_path) { st_medcon_path = new char[1024]; bool path_found = false; std::FILE *file = 0; #ifdef cimg_medcon_path std::strcpy(st_medcon_path,cimg_medcon_path); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } #endif #if cimg_OS==2 const char* pf_path = programfiles_path(); if (!path_found) { std::sprintf(st_medcon_path,".\\medcon.bat"); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) { std::sprintf(st_medcon_path,".\\medcon.exe"); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) { std::sprintf(st_medcon_path,"%s\\XMedCon\\bin\\medcon.bat",pf_path); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) { std::sprintf(st_medcon_path,"%s\\XMedCon\\bin\\medcon.exe",pf_path); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) std::strcpy(st_medcon_path,"medcon.bat"); #else if (!path_found) { std::sprintf(st_medcon_path,"./medcon"); if ((file=std::fopen(st_medcon_path,"r"))!=0) { std::fclose(file); path_found = true; } } if (!path_found) std::strcpy(st_medcon_path,"medcon"); #endif winformat_string(st_medcon_path); } return st_medcon_path; } //! Return path to store temporary files. /** If you are running on a standard Unix or Windows system, this function should return a correct path where temporary files can be stored. If such a path is not auto-detected by this function, you can define the macro \c cimg_temporary_path with a correct path, before including CImg.h in your program : \code #define cimg_temporary_path "/users/thatsme/tmp" #include "CImg.h" int main() { CImg<> img("my_image.jpg"); // Read a JPEG image file (using the defined temporay path). return 0; } \endcode A temporary path is necessary to load and save compressed image formats, using \c convert or \c medcon. \sa imagemagick_path(), get_load_imagemagick(), load_imagemagick(), save_imagemagick(), get_load_dicom(), load_dicom(). **/ inline const char* temporary_path() { #define cimg_test_temporary_path(p) \ if (!path_found) { \ std::sprintf(st_temporary_path,p); \ std::sprintf(tmp,"%s%s%s",st_temporary_path,cimg_OS==2?"\\":"/",filetmp); \ if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } \ } static char *st_temporary_path = 0; if (!st_temporary_path) { st_temporary_path = new char[1024]; bool path_found = false; char tmp[1024], filetmp[512]; std::FILE *file = 0; std::sprintf(filetmp,"CImg%.4d.tmp",std::rand()%10000); #ifdef cimg_temporary_path cimg_test_temporary_path(cimg_temporary_path); #endif char *tmpPath = getenv("TMP"); if (tmpPath==NULL) { tmpPath = getenv("TEMP"); winformat_string(tmpPath); } if (tmpPath!=NULL) cimg_test_temporary_path(tmpPath); #if cimg_OS==2 cimg_test_temporary_path("C:\\WINNT\\Temp"); cimg_test_temporary_path("C:\\WINDOWS\\Temp"); cimg_test_temporary_path("C:\\Temp"); cimg_test_temporary_path("C:"); cimg_test_temporary_path("D:\\WINNT\\Temp"); cimg_test_temporary_path("D:\\WINDOWS\\Temp"); cimg_test_temporary_path("D:\\Temp"); cimg_test_temporary_path("D:"); #else cimg_test_temporary_path("/tmp"); cimg_test_temporary_path("/var/tmp"); #endif if (!path_found) { st_temporary_path[0]='\0'; std::strcpy(tmp,filetmp); if ((file=std::fopen(tmp,"wb"))!=0) { std::fclose(file); std::remove(tmp); path_found = true; } } if (!path_found) throw CImgIOException("cimg::temporary_path() : Unable to find a temporary path accessible for writing\n" "you have to set the macro 'cimg_temporary_path' to a valid path where you have writing access :\n" "#define cimg_temporary_path \"path\" (before including 'CImg.h')"); } return st_temporary_path; } inline const char *filename_split(const char *const filename, char *const body=0) { if (!filename) { if (body) body[0]='\0'; return 0; } int l = cimg::strfind(filename,'.'); if (l>=0) { if (body) { std::strncpy(body,filename,l); body[l]='\0'; }} else { if (body) std::strcpy(body,filename); l=(int)std::strlen(filename)-1; } return filename+l+1; } inline char* filename_number(const char *const filename, const int number, const unsigned int n, char *const string) { if (!filename) { if (string) string[0]='\0'; return 0; } char format[1024],body[1024]; const char *ext = cimg::filename_split(filename,body); if (n>0) std::sprintf(format,"%s_%%.%ud.%s",body,n,ext); else std::sprintf(format,"%s_%%d.%s",body,ext); std::sprintf(string,format,number); return string; } inline std::FILE *fopen(const char *const path,const char *const mode) { if(!path || !mode) throw CImgArgumentException("cimg::fopen() : File '%s' cannot be opened with mode '%s'.", path?path:"(null)",mode?mode:"(null)"); if (path[0]=='-') return (mode[0]=='r')?stdin:stdout; std::FILE *dest = std::fopen(path,mode); if (!dest) throw CImgIOException("cimg::fopen() : File '%s' cannot be opened%s", path,mode[0]=='r'?" for reading.":(mode[0]=='w'?" for writing.":"."),path); return dest; } inline int fclose(std::FILE *file) { warn(!file,"cimg::fclose() : Can't close (null) file"); if (!file || file==stdin || file==stdout) return 0; const int errn=std::fclose(file); warn(errn!=0,"cimg::fclose() : Error %d during file closing",errn); return errn; } template inline int fread(T *const ptr, const unsigned int nmemb, std::FILE *stream) { if (!ptr || nmemb<=0 || !stream) throw CImgArgumentException("cimg::fread() : Can't read %u x %u bytes of file pointer '%p' in buffer '%p'", nmemb,sizeof(T),stream,ptr); const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); unsigned int toread=nmemb, alread=0, ltoread=0, lalread=0; do { ltoread = (toread*sizeof(T))0); cimg::warn(toread>0,"cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb); return alread; } template inline int fwrite(const T *ptr, const unsigned int nmemb, std::FILE *stream) { if (!ptr || !stream) throw CImgArgumentException("cimg::fwrite() : Can't write %u x %u bytes of file pointer '%p' from buffer '%p'", nmemb,sizeof(T),stream,ptr); if (nmemb<=0) return 0; const unsigned long wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); unsigned int towrite=nmemb, alwrite=0, ltowrite=0, lalwrite=0; do { ltowrite = (towrite*sizeof(T))0); cimg::warn(towrite>0,"cimg::fwrite() : File writing problems, only %u/%u elements written",alwrite,nmemb); return alwrite; } // Exchange the values of variables \p a and \p b template inline void swap(T& a,T& b) { T t=a; a=b; b=t; } template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2) { cimg::swap(a1,b1); cimg::swap(a2,b2); } template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3) { cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); } template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4) { cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); } template inline void swap(T1& a1,T1& b1,T2& a2,T2& b2,T3& a3,T3& b3,T4& a4,T4& b4,T5& a5,T5& b5) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); } template 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) { cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6); } template inline void endian_swap(T* const buffer, const unsigned int size) { switch (sizeof(T)) { case 1: break; case 2: { for (unsigned short *ptr = (unsigned short*)buffer+size; ptr>(unsigned short*)buffer;) { const unsigned short val = *(--ptr); *ptr = (val>>8)|((val<<8)); } } break; case 4: { for (unsigned int *ptr = (unsigned int*)buffer+size; ptr>(unsigned int*)buffer;) { const unsigned int val = *(--ptr); *ptr = (val>>24)|((val>>8)&0xff00)|((val<<8)&0xff0000)|(val<<24); } } break; default: { for (T* ptr = buffer+size; ptr>buffer; --ptr) { unsigned char *pb=(unsigned char*)(--ptr), *pe=pb+sizeof(T); for (int i=0; i<(int)sizeof(T)/2; i++) cimg::swap(*(pb++),*(--pe)); } break; } } } template inline T& endian_swap(T& a) { endian_swap(&a,1); return a; } inline const char* option(const char *const name, const int argc, char **argv, const char *defaut, const char *const usage=0) { static bool first=true, visu=false; const char *res = 0; if (first) { first=false; visu = (cimg::option("-h",argc,argv,(char*)0)!=0); visu |= (cimg::option("-help",argc,argv,(char*)0)!=0); visu |= (cimg::option("--help",argc,argv,(char*)0)!=0); } if (!name && visu) { if (usage) { std::fprintf(stderr,"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal); std::fprintf(stderr," : %s",usage); std::fprintf(stderr," (%s, %s)\n\n",__DATE__,__TIME__); } if (defaut) std::fprintf(stderr,"%s\n",defaut); } if (name) { if (argc>0) { int k=0,i; while (k CPU endianness : %s%s Endian%s\n", cimg::t_bold, cimg::endian()?"Big":"Little", cimg::t_normal); std::fprintf(stderr," > Operating System : %s%-13s%s %s('cimg_OS'=%d)%s\n", cimg::t_bold, cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknow"), cimg::t_normal,cimg::t_purple, cimg_OS, cimg::t_normal); #ifdef cimg_use_visualcpp6 std::fprintf(stderr," > Using Visual C++ 6.0 : %s%-13s%s %s('cimg_use_visualcpp6' defined)%s\n", cimg::t_bold,"Yes",cimg::t_normal,cimg::t_purple,cimg::t_normal); #endif std::fprintf(stderr," > Display type : %s%-13s%s %s('cimg_display_type'=%d)%s\n", cimg::t_bold, cimg_display_type==0?"No display":(cimg_display_type==1?"X11":(cimg_display_type==2?"Windows GDI":"Unknow")), cimg::t_normal,cimg::t_purple, cimg_display_type, cimg::t_normal); std::fprintf(stderr," > Color terminal : %s%-13s%s %s('cimg_color_terminal' %s)%s\n", cimg::t_bold, #ifdef cimg_color_terminal "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Debug messages : %s%-13s%s %s('cimg_debug'=%d)%s\n", cimg::t_bold, cimg_debug==0?"No":(cimg_debug==1 || cimg_debug==2?"Yes":(cimg_debug==3?"Yes+":"Unknown")), cimg::t_normal,cimg::t_purple, cimg_debug, cimg::t_normal); #if cimg_display_type==1 std::fprintf(stderr," > Using XShm for X11 : %s%-13s%s %s('cimg_use_xshm' %s)%s\n", cimg::t_bold, #ifdef cimg_use_xshm "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Using XRand for X11 : %s%-13s%s %s('cimg_use_xrandr' %s)%s\n", cimg::t_bold, #ifdef cimg_use_xrandr "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); #endif std::fprintf(stderr," > Using PNG library : %s%-13s%s %s('cimg_use_png' %s)%s\n", cimg::t_bold, #ifdef cimg_use_png "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Using JPEG library : %s%-13s%s %s('cimg_use_jpeg' %s)%s\n", cimg::t_bold, #ifdef cimg_use_jpeg "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Using TIFF library : %s%-13s%s %s('cimg_use_tiff' %s)%s\n", cimg::t_bold, #ifdef cimg_use_tiff "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Using Magick++ library : %s%-13s%s %s('cimg_use_magick' %s)%s\n", cimg::t_bold, #ifdef cimg_use_magick "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::fprintf(stderr," > Using FFTW3 library : %s%-13s%s %s('cimg_use_fftw3' %s)%s\n", cimg::t_bold, #ifdef cimg_use_fftw3 "Yes",cimg::t_normal,cimg::t_purple,"defined", #else "No",cimg::t_normal,cimg::t_purple,"undefined", #endif cimg::t_normal); std::sprintf(tmp,"\"%.1020s\"",cimg::imagemagick_path()); std::fprintf(stderr," > Path of ImageMagick : %s%-13s%s %s('cimg_imagemagick_path'%s)%s\n", cimg::t_bold, tmp, cimg::t_normal, #ifdef cimg_imagemagick_path cimg::t_purple,"=\""cimg_imagemagick_path"\"", #else cimg::t_purple," undefined", #endif cimg::t_normal); std::sprintf(tmp,"\"%.1020s\"",cimg::graphicsmagick_path()); std::fprintf(stderr," > Path of GraphicsMagick : %s%-13s%s %s('cimg_graphicsmagick_path'%s)%s\n", cimg::t_bold, tmp, cimg::t_normal, #ifdef cimg_graphicsmagick_path cimg::t_purple,"=\""cimg_graphicsmagick_path"\"", #else cimg::t_purple," undefined", #endif cimg::t_normal); std::sprintf(tmp,"\"%.1020s\"",cimg::medcon_path()); std::fprintf(stderr," > Path of 'medcon' : %s%-13s%s %s('cimg_medcon_path'%s)%s\n", cimg::t_bold, tmp, cimg::t_normal, #ifdef cimg_medcon_path cimg::t_purple,"=\""cimg_medcon_path"\"", #else cimg::t_purple," undefined", #endif cimg::t_normal); std::sprintf(tmp,"\"%.1020s\"",cimg::temporary_path()); std::fprintf(stderr," > Temporary path : %s%-13s%s %s('cimg_temporary_path'%s)%s\n", cimg::t_bold, tmp, cimg::t_normal, #ifdef cimg_temporary_path cimg::t_purple,"=\""cimg_temporary_path"\"", #else cimg::t_purple," undefined", #endif cimg::t_normal); std::fprintf(stderr,"\n"); } //! Get the value of a system timer with a millisecond precision. inline unsigned long time() { #if cimg_OS==1 struct timeval st_time; gettimeofday(&st_time,0); return (unsigned long)(st_time.tv_usec/1000 + st_time.tv_sec*1000); #elif cimg_OS==2 static SYSTEMTIME st_time; GetSystemTime(&st_time); return (unsigned long)(st_time.wMilliseconds + 1000*(st_time.wSecond + 60*(st_time.wMinute + 60*st_time.wHour))); #else return 0; #endif } //! Sleep for a certain numbers of milliseconds. /** This function frees the CPU ressources during the sleeping time. It may be used to temporize your program properly, without wasting CPU time. \sa wait(), time(). **/ inline void sleep(const unsigned int milliseconds) { #if cimg_OS==1 struct timespec tv; tv.tv_sec = milliseconds/1000; tv.tv_nsec = (milliseconds%1000)*1000000; nanosleep(&tv,0); #elif cimg_OS==2 Sleep(milliseconds); #endif } inline unsigned int wait(const unsigned int milliseconds, unsigned long& timer) { if (!timer) timer = cimg::time(); const unsigned long current_time = cimg::time(); if (current_time>=timer+milliseconds) { timer = current_time; return 0; } const unsigned long time_diff = timer + milliseconds - current_time; timer = current_time + time_diff; cimg::sleep(time_diff); return (unsigned int)time_diff; } //! Wait for a certain number of milliseconds since the last call. /** This function is equivalent to sleep() but the waiting time is computed with regard to the last call of wait(). It may be used to temporize your program properly. \sa sleep(), time(). **/ inline unsigned int wait(const unsigned int milliseconds) { static unsigned long timer = 0; if (!timer) timer = cimg::time(); return wait(milliseconds,timer); } template inline const T rol(const T& a, const unsigned int n=1) { return (T)((a<>((sizeof(T)<<3)-n))); } template inline const T ror(const T& a, const unsigned int n=1) { return (T)((a>>n)|(a<<((sizeof(T)<<3)-n))); } //! Return the absolute value of \p a template inline T abs(const T& a) { return a>=0?a:-a; } inline bool abs(const bool a) { return a; } inline unsigned char abs(const unsigned char a) { return a; } inline unsigned short abs(const unsigned short a) { return a; } inline unsigned int abs(const unsigned int a) { return a; } inline unsigned long abs(const unsigned long a) { return a; } inline double abs(const double a) { return std::fabs(a); } inline float abs(const float a) { return (float)std::fabs((double)a); } inline int abs(const int a) { return std::abs(a); } //! Return the minimum between \p a and \p b. template inline const T& min(const T& a, const T& b) { return a<=b?a:b; } //! Return the minimum between \p a,\p b and \a c. template inline const T& min(const T& a, const T& b, const T& c) { return cimg::min(cimg::min(a,b),c); } //! Return the minimum between \p a,\p b,\p c and \p d. template inline const T& min(const T& a, const T& b, const T& c, const T& d) { return cimg::min(cimg::min(a,b,c),d); } //! Return the maximum between \p a and \p b. template inline const T& max(const T& a, const T& b) { return a>=b?a:b; } //! Return the maximum between \p a,\p b and \p c. template inline const T& max(const T& a, const T& b, const T& c) { return cimg::max(cimg::max(a,b),c); } //! Return the maximum between \p a,\p b,\p c and \p d. template inline const T& max(const T& a, const T& b, const T& c, const T& d) { return cimg::max(cimg::max(a,b,c),d); } //! Return the sign of \p x. template inline T sign(const T& x) { return (x<0)?(T)(-1):(x==0?(T)0:(T)1); } //! Return the nearest power of 2 higher than \p x. template inline unsigned long nearest_pow2(const T& x) { unsigned long i=1; while (x>i) i<<=1; return i; } //! Return \p x modulo \p m (generic modulo). /** This modulo function accepts negative and floating-points modulo numbers \p m. **/ template inline T mod(const T& x, const T& m) { const double dx = (double)x, dm = (double)m; if (x<0) { return (T)(dm+dx+dm*std::floor(-dx/dm)); } return (T)(dx-dm*std::floor(dx/dm)); } inline int mod(const char x, const char m) { return x>=0?x%m:(x%m?m+x%m:0); } inline int mod(const short x, const short m) { return x>=0?x%m:(x%m?m+x%m:0); } inline int mod(const int x, const int m) { return x>=0?x%m:(x%m?m+x%m:0); } inline int mod(const long x, const long m) { return x>=0?x%m:(x%m?m+x%m:0); } inline int mod(const unsigned char x, const unsigned char m) { return x%m; } inline int mod(const unsigned short x, const unsigned short m) { return x%m; } inline int mod(const unsigned int x, const unsigned int m) { return x%m; } inline int mod(const unsigned long x, const unsigned long m) { return x%m; } //! Return minmod(\p a,\p b). /** The operator minmod(\p a,\p b) is defined to be : - minmod(\p a,\p b) = min(\p a,\p b), if (\p a * \p b)>0. - minmod(\p a,\p b) = 0, if (\p a * \p b)<=0 **/ template inline T minmod(const T& a,const T& b) { return a*b<=0?0:(a>0?(aabsb) { const double tmp = absb/absa; return absa*std::sqrt(1.0+tmp*tmp); } else { const double tmp = absa/absb; return (absb==0?0:absb*std::sqrt(1.0+tmp*tmp)); } } // End of the 'cimg' namespace } /* #------------------------------------------------ # # # # Definition of common arithmetical operations # # # #------------------------------------------------ */ #ifdef cimg_use_visualcpp6 template inline CImg operator+(const CImg& img, const t& val) { return CImg(img,false)+=val; } #else template inline CImg::type> operator+(const CImg& img, const t2& val) { typedef typename cimg::largest::type restype; return CImg(img,false)+=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImg operator+(const t& val, const CImg& img) { return img+val; } #else template inline CImg::type> operator+(const t1& val, const CImg& img) { return img+val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator+(const CImgList& list, const t& val) { return CImgList(list)+=val; } #else template inline CImgList::type> operator+(const CImgList& list, const t2& val) { typedef typename cimg::largest::type restype; return CImgList(list)+=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator+(const t& val, const CImgList& list) { return list+val; } #else template inline CImgList::type> operator+(const t1& val, const CImgList& list) { return list+val; } #endif template inline CImg::type> operator+(const CImg& img1, const CImg& img2) { typedef typename cimg::largest::type restype; return CImg(img1,false)+=img2; } template inline CImgList::type> operator+(const CImg& img, const CImgList& list) { typedef typename cimg::largest::type restype; return CImgList(list)+=img; } template inline CImgList::type> operator+(const CImgList& list, const CImg& img) { return img+list; } template inline CImgList::type> operator+(const CImgList& list1, const CImgList& list2) { typedef typename cimg::largest::type restype; return CImgList(list1)+=list2; } #ifdef cimg_use_visualcpp6 template inline CImg operator-(const CImg& img, const t& val) { return CImg(img,false)-=val; } #else template inline CImg::type> operator-(const CImg& img, const t2& val) { typedef typename cimg::largest::type restype; return CImg(img,false)-=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImg operator-(const t& val, const CImg& img) { return CImg(img.width,img.height,img.depth,img.dim,val)-=img; } #else template inline CImg::type> operator-(const t1& val, const CImg& img) { typedef typename cimg::largest::type restype; return CImg(img.width,img.height,img.depth,img.dim,(restype)val)-=img; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator-(const CImgList& list, const t& val) { return CImgList(list)-=val; } #else template inline CImgList::type> operator-(const CImgList& list, const t2& val) { typedef typename cimg::largest::type restype; return CImgList(list)-=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator-(const t& val, const CImgList& list) { CImgList res(list.size); cimglist_for(res,l) res[l] = val-list[l]; return res; } #else template inline CImgList::type> operator-(const t1& val, const CImgList& list) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = val-list[l]; return res; } #endif template inline CImg::type> operator-(const CImg& img1, const CImg& img2) { typedef typename cimg::largest::type restype; return CImg(img1,false)-=img2; } template inline CImgList::type> operator-(const CImg& img, const CImgList& list) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = img-list[l]; return res; } template inline CImgList::type> operator-(const CImgList& list, const CImg& img) { typedef typename cimg::largest::type restype; return CImgList(list)-=img; } template inline CImgList::type> operator-(const CImgList& list1, const CImgList& list2) { typedef typename cimg::largest::type restype; return CImgList(list1)-=list2; } #ifdef cimg_use_visualcpp6 template inline CImg operator*(const CImg& img, const double val) { return CImg(img,false)*=val; } #else template inline CImg::type> operator*(const CImg& img, const t2& val) { typedef typename cimg::largest::type restype; return CImg(img,false)*=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImg operator*(const double val, const CImg& img) { return img*val; } #else template inline CImg::type> operator*(const t1& val, const CImg& img) { return img*val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator*(const CImgList& list, const double val) { return CImgList(list)*=val; } #else template inline CImgList::type> operator*(const CImgList& list, const t2& val) { typedef typename cimg::largest::type restype; return CImgList(list)*=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator*(const double val, const CImgList& list) { return list*val; } #else template inline CImgList::type> operator*(const t1& val, const CImgList& list) { return list*val; } #endif template inline CImg::type> operator*(const CImg& img1, const CImg& img2) { typedef typename cimg::largest::type restype; if (img1.width!=img2.height) throw CImgArgumentException("operator*() : can't multiply a matrix (%ux%u) by a matrix (%ux%u)", img1.width,img1.height,img2.width,img2.height); CImg res(img2.width,img1.height); restype val; cimg_forXY(res,i,j) { val=0; cimg_forX(img1,k) val+=img1(k,j)*img2(i,k); res(i,j) = val; } return res; } template inline CImgList::type> operator*(const CImg& img, const CImgList& list) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = img*list[l]; return res; } template inline CImgList::type> operator*(const CImgList& list, const CImg& img) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = list[l]*img; return res; } template inline CImgList::type> operator*(const CImgList& list1, const CImgList& list2) { typedef typename cimg::largest::type restype; CImgList res(cimg::min(list1.size,list2.size)); cimglist_for(res,l) res[l] = list1[l]*list2[l]; return res; } #ifdef cimg_use_visualcpp6 template inline CImg operator/(const CImg& img, const double val) { return CImg(img,false)/=val; } #else template inline CImg::type> operator/(const CImg& img, const t2& val) { typedef typename cimg::largest::type restype; return CImg(img,false)/=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImg operator/(const double val, CImg& img) { return val*img.get_inverse(); } #else template inline CImg::type> operator/(const t1& val, CImg& img) { return val*img.get_inverse(); } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator/(const CImgList& list, const double val) { return CImgList(list)/=val; } #else template inline CImgList::type> operator/(const CImgList& list, const t2& val) { typedef typename cimg::largest::type restype; return CImgList(list)/=val; } #endif #ifdef cimg_use_visualcpp6 template inline CImgList operator/(const double val, const CImgList& list) { CImgList res(list.size); cimglist_for(res,l) res[l] = val/list[l]; return res; } #else template inline CImgList::type> operator/(const t1& val, const CImgList& list) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = val/list[l]; return res; } #endif template inline CImg::type> operator/(const CImg& img1, const CImg& img2) { typedef typename cimg::largest::type restype; return CImg(img1,false)*=img2.get_inverse(); } template inline CImg::type> operator/(const CImg& img, const CImgList& list) { typedef typename cimg::largest::type restype; CImgList res(list.size); cimglist_for(res,l) res[l] = img/list[l]; return res; } template inline CImgList::type> operator/(const CImgList& list, const CImg& img) { typedef typename cimg::largest::type restype; return CImgList(list)/=img; } template inline CImgList::type> operator/(const CImgList& list1, const CImgList& list2) { typedef typename cimg::largest::type restype; return CImgList(list1)/=list2; } /* #---------------------------------------- # # # # Definition of the CImgStats structure # # # #---------------------------------------- */ //! Class used to compute basic statistics on pixel values of a \ref CImg image. /** Constructing a CImgStats instance from an image CImg or a list CImgList will compute the minimum, maximum and average pixel values of the input object. Optionally, the variance of the pixel values can be computed. Coordinates of the pixels whose values are minimum and maximum are also stored. The example below shows how to use CImgStats objects to retrieve simple statistics of an image : \code const CImg img("my_image.jpg"); // Read JPEG image file. const CImgStats stats(img); // Compute basic statistics on the image. stats.print("My statistics"); // Display statistics. std::printf("Max-Min = %lf",stats.max-stats.min); // Compute the difference between extremum values. \endcode Note that statistics are computed by considering the set of \a scalar values of the image pixels. No vector-valued statistics are computed. **/ struct CImgStats { double min; //!< Minimum of the pixel values. double max; //!< Maximum of the pixel values. double mean; //!< Mean of the pixel values. double variance; //!< Variance of the pixel values. int xmin; //!< X-coordinate of the pixel with minimum value. int ymin; //!< Y-coordinate of the pixel with minimum value. int zmin; //!< Z-coordinate of the pixel with minimum value. int vmin; //!< V-coordinate of the pixel with minimum value. int lmin; //!< Image number (for a list) containing the minimum pixel. int xmax; //!< X-coordinate of the pixel with maximum value. int ymax; //!< Y-coordinate of the pixel with maximum value. int zmax; //!< Z-coordinate of the pixel with maximum value. int vmax; //!< V-coordinate of the pixel with maximum value. int lmax; //!< Image number (for a list) containing the maximum pixel. #ifdef cimgstats_plugin #include cimgstats_plugin #endif //! Default constructor. CImgStats():min(0),max(0),mean(0),variance(0),xmin(-1),ymin(-1),zmin(-1),vmin(-1),lmin(-1), xmax(-1),ymax(-1),zmax(-1),vmax(-1),lmax(-1) {} //! In-place version of the default constructor CImgStats& assign() { min = max = mean = variance = 0; xmin = ymin = zmin = vmin = lmin = xmax = ymax = zmax = vmax = lmax = -1; return *this; } //! Copy constructor. CImgStats(const CImgStats& stats) { assign(stats); }; //! In-place version of the copy constructor. CImgStats& assign(const CImgStats& stats) { min = stats.min; max = stats.max; mean = stats.mean; variance = stats.variance; xmin = stats.xmin; ymin = stats.ymin; zmin = stats.zmin; vmin = stats.vmin; lmin = stats.lmin; xmax = stats.xmax; ymax = stats.ymax; zmax = stats.zmax; vmax = stats.vmax; lmax = stats.lmax; return *this; } //! Constructor that computes statistics of an input image \p img. /** \param img The input image. \param compute_variance If true, the \c variance field is computed, else it is set to 0. **/ template CImgStats(const CImg& img, const bool compute_variance=true) { assign(img,compute_variance); } //! In-place version of the previous constructor. template CImgStats& assign(const CImg& img, const bool compute_variance=true) { if (!img) throw CImgArgumentException("CImgStats::CImgStats() : Specified input image (%u,%u,%u,%u,%p) is empty.", img.width,img.height,img.depth,img.dim,img.data); mean = variance = 0; lmin = lmax = -1; T pmin=img[0], pmax=pmin, *ptrmin=img.data, *ptrmax=ptrmin; cimg_for(img,ptr,T) { const T& a=*ptr; mean+=(double)a; if (apmax) { pmax=a; ptrmax = ptr; } } mean/=img.size(); min=(double)pmin; max=(double)pmax; unsigned long offmin = (unsigned long)(ptrmin-img.data), offmax = (unsigned long)(ptrmax-img.data); const unsigned long whz = img.width*img.height*img.depth, wh = img.width*img.height; vmin = offmin/whz; offmin%=whz; zmin = offmin/wh; offmin%=wh; ymin = offmin/img.width; xmin = offmin%img.width; vmax = offmax/whz; offmax%=whz; zmax = offmax/wh; offmax%=wh; ymax = offmax/img.width; xmax = offmax%img.width; if (compute_variance) { cimg_for(img,ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; } const unsigned int siz = img.size(); if (siz>1) variance/=(siz-1); else variance=0; } return *this; } //! Constructor that computes statistics of an input image list \p list. /** \param list The input list of images. \param compute_variance If true, the \c variance field is computed, else it is set to 0. **/ template CImgStats(const CImgList& list, const bool compute_variance=true) { assign(list,compute_variance); } //! In-place version of the previous constructor. template CImgStats& assign(const CImgList& list, const bool compute_variance=true) { if (!list) throw CImgArgumentException("CImgStats::CImgStats() : Specified input list (%u,%p) is empty.", list.size,list.data); mean = variance = lmin = lmax = 0; T pmin = list[0][0], pmax = pmin, *ptrmin = list[0].data, *ptrmax = ptrmin; int psize = 0; cimglist_for(list,l) { cimg_for(list[l],ptr,T) { const T& a=*ptr; mean+=(double)a; if (apmax) { pmax=a; ptrmax = ptr; lmax = l; } } psize+=list[l].size(); } mean/=psize; min=(double)pmin; max=(double)pmax; const CImg &imin = list[lmin], &imax = list[lmax]; unsigned long offmin = (ptrmin-imin.data), offmax = (ptrmax-imax.data); const unsigned long whz1 = imin.width*imin.height*imin.depth, wh1 = imin.width*imin.height; vmin = offmin/whz1; offmin%=whz1; zmin = offmin/wh1; offmin%=wh1; ymin = offmin/imin.width; xmin = offmin%imin.width; const unsigned long whz2 = imax.width*imax.height*imax.depth, wh2 = imax.width*imax.height; vmax = offmax/whz2; offmax%=whz2; zmax = offmax/wh2; offmax%=wh2; ymax = offmax/imax.width; xmax = offmax%imax.width; if (compute_variance) { cimglist_for(list,l) cimg_for(list[l],ptr,T) { const double tmpf=(*ptr)-mean; variance+=tmpf*tmpf; } if (psize>1) variance/=(psize-1); else variance=0; } return *this; } //! Assignment operator. CImgStats& operator=(const CImgStats& stats) { return assign(stats); } //! Return true if the current instance contains valid statistics bool is_empty() const { return (xmin>=0 && ymin>=0 && zmin>=0 && vmin>=0 && xmax>=0 && ymax>=0 && zmax>=0 && vmax>=0); } //! Casting operator operator bool() const { return !is_empty(); } //! Print the current statistics. /** Printing is done on the standard error output. **/ const CImgStats& print(const char* title=0) const { if (lmin>=0 && lmax>=0) std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, " "pmin=[%d](%d,%d,%d,%d), pmax=[%d](%d,%d,%d,%d) }\n", title?title:"CImgStats",(void*)this,min,mean,variance,max, lmin,xmin,ymin,zmin,vmin,lmax,xmax,ymax,zmax,vmax); else std::fprintf(stderr,"%-8s(this=%p) : { min=%g, mean=%g [var=%g], max=%g, " "pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d) }\n", title?title:"CImgStats",(void*)this,min,mean,variance,max, xmin,ymin,zmin,vmin,xmax,ymax,zmax,vmax); return *this; } }; /* #------------------------------------------- # # # # Definition of the CImgDisplay structure # # # #------------------------------------------- */ //! This class represents a window which can display \ref CImg images and handles mouse and keyboard events. /** Creating a \c CImgDisplay instance opens a window that can be used to display a \c CImg image of a \c CImgList image list inside. When a display is created, associated window events (such as mouse motion, keyboard and window size changes) are handled and can be easily detected by testing specific \c CImgDisplay data fields. See \ref cimg_displays for a complete tutorial on using the \c CImgDisplay class. **/ struct CImgDisplay { //! Width of the display unsigned int width; //! Height of the display unsigned int height; //! Normalization type used for the display unsigned int normalization; //! Range of events detected by the display unsigned int events; //! Display title char* title; //! X-pos of the display on the screen volatile int window_x; //! Y-pos of the display on the screen volatile int window_y; //! Width of the underlying window volatile unsigned int window_width; //! Height of the underlying window volatile unsigned int window_height; //! X-coordinate of the mouse pointer on the display volatile int mouse_x; //! Y-coordinate of the mouse pointer on the display volatile int mouse_y; //! Button state of the mouse volatile unsigned int buttons[256]; volatile unsigned int& button; //! Wheel state of the mouse volatile int wheel; //! Key value if pressed volatile unsigned int& key; volatile unsigned int keys[256]; //! Key value if released volatile unsigned int& released_key; volatile unsigned int released_keys[256]; //! Closed state of the window volatile bool is_closed; //! Resized state of the window volatile bool is_resized; //! Moved state of the window volatile bool is_moved; //! Event state of the window volatile bool is_event; //! Fullscreen state of the display bool is_fullscreen; float fps_fps, min, max; unsigned long timer, fps_frames, fps_timer; #ifdef cimgdisplay_plugin #include cimgdisplay_plugin #endif //! Create an empty display window. CImgDisplay(): width(0),height(0),normalization(0),events(0),title(0), window_x(0),window_y(0),window_width(0),window_height(0), mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys), is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false), min(0),max(0) {} //! Create a display window with a specified size \p pwidth x \p height. /** \param dimw : Width of the display window. \param dimh : Height of the display window. \param title : Title of the display window. \param normalization_type : Normalization type of the display window (see CImgDisplay::normalize). \param events_type : Type of events handled by the display window. \param fullscreen_flag : Fullscreen mode. \param closed_flag : Initially visible mode. A black image will be initially displayed in the display window. **/ CImgDisplay(const unsigned int dimw, const unsigned int dimh, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false): width(0),height(0),normalization(0),events(0),title(0), window_x(0),window_y(0),window_width(0),window_height(0), mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys), is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false), min(0),max(0) { assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag); } //! Create a display window from an image. /** \param img : Image that will be used to create the display window. \param title : Title of the display window \param normalization_type : Normalization type of the display window. \param events_type : Type of events handled by the display window. \param fullscreen_flag : Fullscreen mode. \param closed_flag : Initially visible mode. **/ template CImgDisplay(const CImg& img, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false): width(0),height(0),normalization(0),events(0),title(0), window_x(0),window_y(0),window_width(0),window_height(0), mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys), is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) { assign(img,title,normalization_type,events_type,fullscreen_flag,closed_flag); } //! Create a display window from an image list. /** \param list : The list of images to display. \param title : Title of the display window \param normalization_type : Normalization type of the display window. \param events_type : Type of events handled by the display window. \param fullscreen_flag : Fullscreen mode. \param closed_flag : Initially visible mode. **/ template CImgDisplay(const CImgList& list,const char *title=0, const unsigned int normalization_type=3,const unsigned int events_type=3, const bool fullscreen_flag=false,const bool closed_flag=false): width(0),height(0),normalization(0),events(0),title(0), window_x(0),window_y(0),window_width(0),window_height(0), mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys), is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) { assign(list,title,normalization_type,events_type,fullscreen_flag,closed_flag); } //! Create a display window by copying another one. /** \param win : Display window to copy. \param title : Title of the new display window. **/ CImgDisplay(const CImgDisplay& disp): width(0),height(0),normalization(0),events(0),title(0), window_x(0),window_y(0),window_width(0),window_height(0), mouse_x(0),mouse_y(0),button(*buttons),wheel(0),key(*keys),released_key(*released_keys), is_closed(true),is_resized(false),is_moved(false),is_event(false),is_fullscreen(false),min(0),max(0) { assign(disp); } //! Destructor ~CImgDisplay() { assign(); } //! Assignment operator CImgDisplay& operator=(const CImgDisplay& disp) { return assign(disp); } //! Return true is display is empty bool is_empty() const { return (!width || !height); } //! Return false if display is empty operator bool() const { return !is_empty(); } //! Return display width int dimx() const { return (int)width; } //! Return display height int dimy() const { return (int)height; } //! Return display window width int window_dimx() const { return (int)window_width; } //! Return display window height int window_dimy() const { return (int)window_height; } //! Return X-coordinate of the window int window_posx() const { return window_x; } //! Return Y-coordinate of the window int window_posy() const { return window_y; } //! Synchronized waiting function. Same as cimg::wait(). /** \see cimg::wait() **/ CImgDisplay& wait(const unsigned int milliseconds) { cimg::wait(milliseconds, timer); return *this; } //! Wait for an event occuring on the current display CImgDisplay& wait() { if (!is_empty()) wait(*this); return *this; } //! Wait for any event occuring on the display \c disp1 static void wait(CImgDisplay& disp1) { disp1.is_event = 0; while (!disp1.is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1 or \c disp2 static void wait(CImgDisplay& disp1, CImgDisplay& disp2) { disp1.is_event = disp2.is_event = 0; while (!disp1.is_event && !disp2.is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2 or \c disp3 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) { disp1.is_event = disp2.is_event = disp3.is_event = 0; while (!disp1.is_event && !disp2.is_event && !disp3.is_event) wait_all(); } //! Wait for any event occuring either on the display \c disp1, \c disp2, \c disp3 or \c disp4 static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) { disp1.is_event = disp2.is_event = disp3.is_event = disp4.is_event = 0; while (!disp1.is_event && !disp2.is_event && !disp3.is_event && !disp4.is_event) wait_all(); } //! Return the frame per second rate float frames_per_second() { if (!fps_timer) fps_timer = cimg::time(); const float delta = (cimg::time()-fps_timer)/1000.0f; fps_frames++; if (delta>=1.0f) { fps_fps = fps_frames/delta; fps_frames = 0; fps_timer = cimg::time(); } return fps_fps; } //! Display an image list CImgList into a display window. /** First, all images of the list are appended into a single image used for visualization, then this image is displayed in the current display window. \param list : The list of images to display. \param axe : The axe used to append the image for visualization. Can be 'x' (default),'y','z' or 'v'. \param align : Defines the relative alignment of images when displaying images of different sizes. Can be '\p c' (centered, which is the default), '\p p' (top alignment) and '\p n' (bottom aligment). \see CImg::get_append() **/ template CImgDisplay& display(const CImgList& list,const char axe='x',const char align='c') { return display(list.get_append(axe,align)); } //! Display an image CImg into a display window. template CImgDisplay& operator<<(const CImg& img) { return display(img); } //! Display an image CImg into a display window. template CImgDisplay& operator<<(const CImgList& list) { return display(list); } //! Resize a display window with the size of an image. /** \param img : Input image. \p image.width and \p image.height give the new dimensions of the display window. \param redraw : If \p true (default), the current displayed image in the display window will be bloc-interpolated to fit the new dimensions. If \p false, a black image will be drawn in the resized window. \see CImgDisplay::is_resized, CImgDisplay::resizedimx(), CImgDisplay::resizedimy() **/ template CImgDisplay& resize(const CImg& img, const bool redraw=true) { return resize(img.width,img.height,redraw); } //! Resize a display window using the size of the given display \p disp CImgDisplay& resize(const CImgDisplay& disp, const bool redraw=true) { return resize(disp.width,disp.height,redraw); } //! Resize a display window in its current size. CImgDisplay& resize(const bool redraw=true) { resize(window_width,window_height,redraw); return *this; } //! Display a 3d object template CImgDisplay& display_object3d(const tp& points, const CImgList& primitives, const CImgList& colors, const to& opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes = true, float *const pose_matrix=0) { CImg(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this, centering,render_static,render_motion, double_sided,focale,ambient_light,display_axes,pose_matrix); return *this; } //! Display a 3D object. template CImgDisplay& display_object3d(const tp& points, const CImgList& primitives, const CImgList& colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const float opacity=1.0f, const bool display_axes = true, float *const pose_matrix=0) { typedef typename cimg::largest::type to; CImg(width,height,1,3,0).display_object3d(points,primitives,colors, CImg(primitives.size)=(to)opacity,*this, centering,render_static,render_motion, double_sided,focale,ambient_light,display_axes,pose_matrix); return *this; } //! Toggle fullscreen mode CImgDisplay& toggle_fullscreen() { return assign(width,height,title,normalization,events,!is_fullscreen,is_closed); } // Inner routine used for fast resizing of buffer to display size. template static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, t *ptrd, const unsigned int wd, const unsigned int hd) { unsigned int *const offx = new unsigned int[wd], *const offy = new unsigned int[hd+1], *poffx, *poffy; float s, curr, old; s = (float)ws/wd; poffx = offx; curr=0; for (unsigned int x=0; x CImgDisplay& assign(const CImg& img, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { fps_timer = 0*(unsigned long)(img.width + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag); return assign(0,0); } //! In-place version of the previous constructor template CImgDisplay& assign(const CImgList& list, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { fps_timer = 0*(unsigned long)(list.size + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag); return assign(0,0); } //! In-place version of the previous constructor CImgDisplay& assign(const CImgDisplay &disp) { return assign(disp.width,disp.height); } //! Display an image in a window. template CImgDisplay& display(const CImg& img) { fps_timer = 0*img.width; return *this; } //! Resize window CImgDisplay& resize(const int width, const int height, const bool redraw=true) { fps_timer = 0*width*height*(int)redraw; return *this; } //! Move window CImgDisplay& move(const int posx, const int posy) { fps_timer = 0*posx*posy; return *this; } //! Move mouse pointer to a specific location CImgDisplay& set_mouse(const int posx, const int posy) { fps_timer = 0*posx*posy; return *this; } //! Hide mouse pointer CImgDisplay& hide_mouse() { return *this; } //! Show mouse pointer CImgDisplay& show_mouse() { return *this; } //! Wait for a window event in any CImg window static void wait_all() {} //! Show a closed display CImgDisplay& show() { return *this; } //! Close a visible display CImgDisplay& close() { return *this; } //! Set the window title CImgDisplay& set_title(const char *format,...) { fps_timer = 0*(unsigned long)format; return *this; } //! Re-paint image content in window CImgDisplay& paint() { return *this; } //! Render image buffer into GDI native image format template CImgDisplay& render(const CImg& img) { fps_timer = 0*img.width; return *this; } // X11-based display //------------------- #elif cimg_display_type==1 void *data; Window window; Window background_window; XImage *image; Colormap colormap; Atom wm_delete_window, wm_delete_protocol; #ifdef cimg_use_xshm XShmSegmentInfo *shminfo; #endif static int screen_dimx() { int res = 0; if (!cimg::X11attr().display) { Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimx() : Can't open X11 display"); res = DisplayWidth(disp,DefaultScreen(disp)); XCloseDisplay(disp); } else { #ifdef cimg_use_xrandr if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width; else #endif res = DisplayWidth(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); } return res; } static int screen_dimy() { int res = 0; if (!cimg::X11attr().display) { Display *disp = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); if (!disp) throw CImgDisplayException("CImgDisplay::screen_dimy() : Can't open X11 display"); res = DisplayHeight(disp,DefaultScreen(disp)); XCloseDisplay(disp); } else { #ifdef cimg_use_xrandr if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) res = cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height; else #endif res = DisplayHeight(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); } return res; } CImgDisplay& assign() { if (!is_empty()) { pthread_mutex_lock(cimg::X11attr().mutex); // Remove display window from event thread list unsigned int i; for (i=0; ishmaddr); shmctl(shminfo->shmid,IPC_RMID,0); delete shminfo; shminfo = 0; } else #endif XDestroyImage(image); data = 0; image = 0; if (cimg::X11attr().nb_bits==8) XFreeColormap(cimg::X11attr().display,colormap); colormap = 0; XSync(cimg::X11attr().display, False); // Reset display variables if (title) delete[] title; width = height = normalization = events = 0; is_fullscreen = is_resized = is_moved = is_event = false; is_closed = true; title = 0; window_x = window_y = window_width = window_height = mouse_x = mouse_y = wheel = 0; std::memset((void*)buttons,0,256*sizeof(unsigned int)); std::memset((void*)keys,0,256*sizeof(unsigned int)); std::memset((void*)released_keys,0,256*sizeof(unsigned int)); min = max = 0; // End event thread and close display if necessary if (!cimg::X11attr().nb_wins) { // Kill event thread pthread_cancel(*cimg::X11attr().event_thread); pthread_mutex_unlock(cimg::X11attr().mutex); pthread_join(*cimg::X11attr().event_thread,0); delete cimg::X11attr().event_thread; cimg::X11attr().event_thread = 0; pthread_mutex_destroy(cimg::X11attr().mutex); delete cimg::X11attr().mutex; cimg::X11attr().mutex = 0; XSync(cimg::X11attr().display, False); XCloseDisplay(cimg::X11attr().display); cimg::X11attr().display = 0; delete cimg::X11attr().gc; cimg::X11attr().gc = 0; } else pthread_mutex_unlock(cimg::X11attr().mutex); } return *this; } CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!dimw || !dimh) return assign(); _assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag); min = max = 0; std::memset(data,0,(cimg::X11attr().nb_bits==8?sizeof(unsigned char): (cimg::X11attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))*width*height); return paint(); } template CImgDisplay& assign(const CImg& img, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!img) return assign(); CImg tmp; const CImg& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag); if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; } return render(nimg).paint(); } template CImgDisplay& assign(const CImgList& list, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; const CImg img = list.get_append('x','p'), &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag); if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; } return render(nimg).paint(); } CImgDisplay& assign(const CImgDisplay& win) { if (!win) return assign(); _assign(win.width,win.height,win.title,win.normalization,win.events,win.is_fullscreen,win.is_closed); std::memcpy(data,win.data,(cimg::X11attr().nb_bits==8?sizeof(unsigned char): cimg::X11attr().nb_bits==16?sizeof(unsigned short): sizeof(unsigned int))*width*height); return paint(); } template CImgDisplay& display(const CImg& img) { if (is_empty()) return *this; return render(img).paint(false); } CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { if (!nwidth || !nheight) return assign(); if (is_empty()) return assign(cimg::max(nwidth,0),cimg::max(nheight,0)); const unsigned int tmpdimx = (nwidth>0)?nwidth:(-nwidth*width/100), tmpdimy = (nheight>0)?nheight:(-nheight*height/100), dimx = cimg::min(tmpdimx?tmpdimx:1,(unsigned int)screen_dimx()), dimy = cimg::min(tmpdimy?tmpdimy:1,(unsigned int)screen_dimy()); const bool is_disp_different = (width!=dimx || height!=dimy), is_win_different = (window_width!=dimx || window_height!=dimy); if (is_disp_different || is_win_different) { pthread_mutex_lock(cimg::X11attr().mutex); XResizeWindow(cimg::X11attr().display,window,dimx,dimy); window_width = dimx; window_height = dimy; is_resized = false; if (is_disp_different) { switch (cimg::X11attr().nb_bits) { case 8: { unsigned char foo=0; _resize(foo,dimx,dimy,redraw); } break; case 16: { unsigned short foo=0; _resize(foo,dimx,dimy,redraw); } break; default: { unsigned int foo=0; _resize(foo,dimx,dimy,redraw); } break; } width = dimx; height = dimy; } pthread_mutex_unlock(cimg::X11attr().mutex); if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2); if (redraw) return paint(); } return *this; } CImgDisplay& move(const int posx, const int posy) { if (is_empty()) return *this; show(); pthread_mutex_lock(cimg::X11attr().mutex); XMoveWindow(cimg::X11attr().display,window,posx,posy); is_moved = false; window_x = posx; window_y = posy; pthread_mutex_unlock(cimg::X11attr().mutex); return paint(); } CImgDisplay& set_mouse(const int posx, const int posy) { if (!is_closed && posx>=0 && posy>=0) { pthread_mutex_lock(cimg::X11attr().mutex); XWarpPointer(cimg::X11attr().display,None,window,0,0,0,0,posx,posy); is_moved = false; mouse_x = posx; mouse_y = posy; XSync(cimg::X11attr().display, False); pthread_mutex_unlock(cimg::X11attr().mutex); } return *this; } CImgDisplay& hide_mouse() { if (cimg::X11attr().display) { pthread_mutex_lock(cimg::X11attr().mutex); const char pix_data[8] = { 0 }; XColor col; col.red = col.green = col.blue = 0; Pixmap pix = XCreateBitmapFromData(cimg::X11attr().display,window,pix_data,8,8); Cursor cur = XCreatePixmapCursor(cimg::X11attr().display,pix,pix,&col,&col,0,0); XFreePixmap(cimg::X11attr().display,pix); XDefineCursor(cimg::X11attr().display,window,cur); pthread_mutex_unlock(cimg::X11attr().mutex); } return *this; } CImgDisplay& show_mouse() { if (cimg::X11attr().display) { pthread_mutex_lock(cimg::X11attr().mutex); XDefineCursor(cimg::X11attr().display,window,None); pthread_mutex_unlock(cimg::X11attr().mutex); } return *this; } static void wait_all() { if (cimg::X11attr().display) { pthread_mutex_lock(cimg::X11attr().mutex); bool flag = true; XEvent event; while (flag) { for (unsigned int i=0; iis_event = false; const unsigned int xevent_type = (cimg::X11attr().wins[i]->events)&3; const unsigned int emask = ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)| ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)| ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0); XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask); } XNextEvent(cimg::X11attr().display, &event); for (unsigned int i=0; iis_closed && event.xany.window==cimg::X11attr().wins[i]->window) { cimg::X11attr().wins[i]->_handle_events(&event); if (cimg::X11attr().wins[i]->is_event) flag = false; } } pthread_mutex_unlock(cimg::X11attr().mutex); } } CImgDisplay& show() { if (is_empty()) return *this; if (is_closed) { pthread_mutex_lock(cimg::X11attr().mutex); if (is_fullscreen) _init_fullscreen(); _map_window(); is_closed = false; pthread_mutex_unlock(cimg::X11attr().mutex); } return paint(); } CImgDisplay& close() { if (is_empty()) return *this; if (!is_closed) { pthread_mutex_lock(cimg::X11attr().mutex); if (is_fullscreen) _desinit_fullscreen(); XUnmapWindow(cimg::X11attr().display,window); window_x = window_y = -1; is_closed = true; pthread_mutex_unlock(cimg::X11attr().mutex); } return *this; } CImgDisplay& set_title(const char *format,...) { if (is_empty()) return *this; char tmp[1024]={0}; va_list ap; va_start(ap, format); std::vsprintf(tmp,format,ap); va_end(ap); if (title) delete[] title; const int s = cimg::strlen(tmp)+1; title = new char[s]; std::memcpy(title,tmp,s*sizeof(char)); pthread_mutex_lock(cimg::X11attr().mutex); XStoreName(cimg::X11attr().display,window,tmp); pthread_mutex_unlock(cimg::X11attr().mutex); return *this; } CImgDisplay& paint(const bool wait_expose=true) { if (is_empty()) return *this; pthread_mutex_lock(cimg::X11attr().mutex); _paint(wait_expose); pthread_mutex_unlock(cimg::X11attr().mutex); return *this; } template CImgDisplay& render(const CImg& img, const bool flag8=false) { if (is_empty()) return *this; if (!img) throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.", img.width,img.height,img.depth,img.dim,img.data); if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2)); if (cimg::X11attr().nb_bits==8 && (img.width!=width || img.height!=height)) return render(img.get_resize(width,height,1,-100,1)); if (cimg::X11attr().nb_bits==8 && !flag8 && img.dim==3) return render(img.get_RGBtoLUT(true),true); const unsigned int xymax = img.width*img.height; const T *data1 = img.ptr(), *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1, *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1; if (cimg::X11attr().blue_first) cimg::swap(data1,data3); pthread_mutex_lock(cimg::X11attr().mutex); if (!normalization || (normalization==3 && cimg::type::id()==cimg::type::id())) { min = max = 0; switch (cimg::X11attr().nb_bits) { case 8: { _set_colormap(colormap,img.dim); unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; switch (img.dim) { case 1: for (unsigned int xy=0; xy>4); } break; default: for (unsigned int xy=0; xy>5)<<2) | (B>>6); } break; } if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; } } break; case 16: { unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy>2; *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3); *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); } else for (unsigned int xy=0; xy>2; *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3); } if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; } } break; default: { unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } else { min = (float)cimg::type::min(); max = (float)cimg::type::max(); } } else if ((min>max) || normalization==1) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } const float delta = max-min, mm = delta?delta:1.0f; switch (cimg::X11attr().nb_bits) { case 8: { _set_colormap(colormap,img.dim); unsigned char *const ndata = (img.width==width && img.height==height)?(unsigned char*)data:new unsigned char[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; switch (img.dim) { case 1: for (unsigned int xy=0; xy>4); } break; default: for (unsigned int xy=0; xy>5)<<2) | (B>>6); } break; } if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned char*)data,width,height); delete[] ndata; } } break; case 16: { unsigned short *const ndata = (img.width==width && img.height==height)?(unsigned short*)data:new unsigned short[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; const unsigned int M = 248; if (cimg::X11attr().byte_order) for (unsigned int xy=0; xy>2; *(ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm)&M | (G>>3); *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3); } else for (unsigned int xy=0; xy>2; *(ptrd++) = (G<<5) | ((unsigned char)(255*(*(data3++)-min)/mm)>>3); *(ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm)&M | (G>>3); } if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned short*)data,width,height); delete[] ndata; } } break; default: { unsigned int *const ndata = (img.width==width && img.height==height)?(unsigned int*)data:new unsigned int[img.width*img.height]; unsigned char *ptrd = (unsigned char*)ndata; if (cimg::X11attr().byte_order) for (unsigned int xy=0; xyred_maskblue_mask) cimg::X11attr().blue_first = true; cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display); XFree(vinfo); pthread_mutex_lock(cimg::X11attr().mutex); cimg::X11attr().event_thread = new pthread_t; pthread_create(cimg::X11attr().event_thread,0,_events_thread,0); } else pthread_mutex_lock(cimg::X11attr().mutex); // Set display variables width = cimg::min(dimw,(unsigned int)screen_dimx()); height = cimg::min(dimh,(unsigned int)screen_dimy()); normalization = normalization_type%4; events = events_type%4; is_fullscreen = fullscreen_flag; title = tmp_title; window_x = window_y = wheel = 0; mouse_x = mouse_y = -1; std::memset((void*)buttons,0,256*sizeof(unsigned int)); std::memset((void*)keys,0,256*sizeof(unsigned int)); std::memset((void*)released_keys,0,256*sizeof(unsigned int)); is_resized = is_moved = is_event = false; is_closed = closed_flag; fps_timer = fps_frames = timer = 0; fps_fps = 0; // Create X11 window and palette (if 8bits display) if (is_fullscreen) { _init_fullscreen(); const unsigned int sx = screen_dimx(), sy = screen_dimy(); XSetWindowAttributes winattr; winattr.override_redirect = True; window = XCreateWindow(cimg::X11attr().display, RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), (sx-width)/2,(sy-height)/2, width,height,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); } else window = XCreateSimpleWindow(cimg::X11attr().display, RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), 0,0,width,height,2,0,0x0L); XStoreName(cimg::X11attr().display,window,title?title:" "); if (cimg::X11attr().nb_bits==8) { colormap = XCreateColormap(cimg::X11attr().display,window,DefaultVisual(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display)),AllocAll); _set_colormap(colormap,3); XSetWindowColormap(cimg::X11attr().display,window,colormap); } window_width = width; window_height = height; // Create XImage const unsigned int bufsize = width*height*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4)); #ifdef cimg_use_xshm shminfo = 0; if (XShmQueryExtension(cimg::X11attr().display)) { shminfo = new XShmSegmentInfo; image = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), cimg::X11attr().nb_bits,ZPixmap,0,shminfo,width,height); if (!image) { delete shminfo; shminfo = 0; } else { shminfo->shmid = shmget(IPC_PRIVATE, bufsize, IPC_CREAT | 0777); if (shminfo->shmid==-1) { XDestroyImage(image); delete shminfo; shminfo = 0; } else { shminfo->shmaddr = image->data = (char*)(data = shmat(shminfo->shmid,0,0)); if (shminfo->shmaddr==(char*)-1) { shmctl(shminfo->shmid,IPC_RMID,0); XDestroyImage(image); delete shminfo; shminfo = 0; } else { shminfo->readOnly = False; cimg::X11attr().shm_enabled = true; XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); XShmAttach(cimg::X11attr().display, shminfo); XSync(cimg::X11attr().display, False); XSetErrorHandler(oldXErrorHandler); if (!cimg::X11attr().shm_enabled) { shmdt(shminfo->shmaddr); shmctl(shminfo->shmid,IPC_RMID,0); XDestroyImage(image); delete shminfo; shminfo = 0; } } } } } if (!shminfo) #endif { data = std::malloc(bufsize); image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,width,height,8,0); } if (!is_closed) _map_window(); else { window_x = window_y = cimg::type::min(); } if (events) { wm_delete_window = XInternAtom(cimg::X11attr().display, "WM_DELETE_WINDOW", False); wm_delete_protocol = XInternAtom(cimg::X11attr().display, "WM_PROTOCOLS", False); XSetWMProtocols(cimg::X11attr().display, window, &wm_delete_window, 1); if (is_fullscreen) XGrabKeyboard(cimg::X11attr().display, window, True, GrabModeAsync, GrabModeAsync, CurrentTime); } cimg::X11attr().wins[cimg::X11attr().nb_wins++]=this; pthread_mutex_unlock(cimg::X11attr().mutex); } void _map_window() { XWindowAttributes attr; XEvent event; XSelectInput(cimg::X11attr().display,window,ExposureMask | StructureNotifyMask); bool exposed = false, mapped = false; XMapRaised(cimg::X11attr().display,window); XSync(cimg::X11attr().display,False); do { XWindowEvent(cimg::X11attr().display,window,StructureNotifyMask | ExposureMask,&event); switch (event.type) { case MapNotify: mapped = true; break; case Expose: exposed = true; break; default: XSync(cimg::X11attr().display, False); cimg::sleep(10); } } while (!(exposed && mapped)); do { XGetWindowAttributes(cimg::X11attr().display, window, &attr); if (attr.map_state!=IsViewable) { XSync(cimg::X11attr().display,False); cimg::sleep(10); } } while (attr.map_state != IsViewable); window_x = attr.x; window_y = attr.y; } void _set_colormap(Colormap& colormap, const unsigned int dim) { XColor palette[256]; switch (dim) { case 1: // palette for greyscale images for (unsigned int index=0; index<256; index++) { palette[index].pixel = index; palette[index].red = palette[index].green = palette[index].blue = index<<8; palette[index].flags = DoRed | DoGreen | DoBlue; } break; case 2: // palette for RG images for (unsigned int index=0, r=8; r<256; r+=16) for (unsigned int g=8; g<256; g+=16) { palette[index].pixel = index; palette[index].red = palette[index].blue = r<<8; palette[index].green = g<<8; palette[index++].flags = DoRed | DoGreen | DoBlue; } break; default: // palette for RGB images for (unsigned int index=0, r=16; r<256; r+=32) for (unsigned int g=16; g<256; g+=32) for (unsigned int b=32; b<256; b+=64) { palette[index].pixel = index; palette[index].red = r<<8; palette[index].green = g<<8; palette[index].blue = b<<8; palette[index++].flags = DoRed | DoGreen | DoBlue; } break; } XStoreColors(cimg::X11attr().display,colormap,palette,256); } void _paint(const bool wait_expose=true) { if (!is_closed) { if (wait_expose) { static XEvent event; event.xexpose.type = Expose; event.xexpose.serial = 0; event.xexpose.send_event = True; event.xexpose.display = cimg::X11attr().display; event.xexpose.window = window; event.xexpose.x = 0; event.xexpose.y = 0; event.xexpose.width = (int)width; event.xexpose.height = (int)height; event.xexpose.count = 0; XSendEvent(cimg::X11attr().display, window, False, 0, &event); } else { #ifdef cimg_use_xshm if (shminfo) XShmPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height,False); else #endif XPutImage(cimg::X11attr().display,window,*cimg::X11attr().gc,image,0,0,0,0,width,height); XSync(cimg::X11attr().display, False); } } } template void _resize(T foo, const unsigned int ndimx, const unsigned int ndimy, const bool redraw) { foo = 0; #ifdef cimg_use_xshm if (shminfo) { XShmSegmentInfo *nshminfo = new XShmSegmentInfo; XImage *nimage = XShmCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), cimg::X11attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy); if (!nimage) { delete nshminfo; return; } else { nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777); if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; } else { nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0); if (nshminfo->shmaddr==(char*)-1) { shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; } else { nshminfo->readOnly = False; cimg::X11attr().shm_enabled = true; XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); XShmAttach(cimg::X11attr().display, nshminfo); XSync(cimg::X11attr().display, False); XSetErrorHandler(oldXErrorHandler); if (!cimg::X11attr().shm_enabled) { shmdt(nshminfo->shmaddr); shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; } else { T *const ndata = (T*)nimage->data; if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy); else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); XShmDetach(cimg::X11attr().display, shminfo); XDestroyImage(image); shmdt(shminfo->shmaddr); shmctl(shminfo->shmid,IPC_RMID,0); delete shminfo; shminfo = nshminfo; image = nimage; data = (void*)ndata; } } } } } else #endif { T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T)); if (redraw) _render_resize((T*)data,width,height,ndata,ndimx,ndimy); else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); data = (void*)ndata; XDestroyImage(image); image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), cimg::X11attr().nb_bits,ZPixmap,0,(char*)data,ndimx,ndimy,8,0); } } void _init_fullscreen() { background_window = 0; if (is_fullscreen && !is_closed) { #ifdef cimg_use_xrandr int foo; if (XRRQueryExtension(cimg::X11attr().display,&foo,&foo)) { XRRRotations(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display), &cimg::X11attr().curr_rotation); if (!cimg::X11attr().resolutions) { cimg::X11attr().resolutions = XRRSizes(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display),&foo); cimg::X11attr().nb_resolutions = (unsigned int)foo; } if (cimg::X11attr().resolutions) { cimg::X11attr().curr_resolution = 0; for (unsigned int i=0; i=width && nh>=height && nw<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].width) && nh<=(unsigned int)(cimg::X11attr().resolutions[cimg::X11attr().curr_resolution].height)) cimg::X11attr().curr_resolution = i; } if (cimg::X11attr().curr_resolution>0) { XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display)); XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display), cimg::X11attr().curr_resolution, cimg::X11attr().curr_rotation, CurrentTime); XRRFreeScreenConfigInfo(config); XSync(cimg::X11attr().display, False); } } } cimg::warn(!cimg::X11attr().resolutions,"CImgDisplay::_create_window() : Xrandr extension is not supported by the X server."); #endif const unsigned int sx = screen_dimx(), sy = screen_dimy(); XSetWindowAttributes winattr; winattr.override_redirect = True; if (sx!=width || sy!=height) { background_window = XCreateWindow(cimg::X11attr().display, RootWindow(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)),0,0, sx,sy,0,0,InputOutput,CopyFromParent,CWOverrideRedirect,&winattr); const unsigned int bufsize = sx*sy*(cimg::X11attr().nb_bits==8?1:(cimg::X11attr().nb_bits==16?2:4)); void *background_data = std::malloc(bufsize); std::memset(background_data,0,bufsize); XImage *background_image = XCreateImage(cimg::X11attr().display,DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)), cimg::X11attr().nb_bits,ZPixmap,0,(char*)background_data,sx,sy,8,0); XEvent event; XSelectInput(cimg::X11attr().display,background_window,StructureNotifyMask); XMapRaised(cimg::X11attr().display,background_window); do XWindowEvent(cimg::X11attr().display,background_window,StructureNotifyMask,&event); while (event.type!=MapNotify); #ifdef cimg_use_xshm if (shminfo) XShmPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy,False); else #endif XPutImage(cimg::X11attr().display,background_window,*cimg::X11attr().gc,background_image,0,0,0,0,sx,sy); XWindowAttributes attr; XGetWindowAttributes(cimg::X11attr().display, background_window, &attr); while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False); XDestroyImage(background_image); } } } void _desinit_fullscreen() { if (is_fullscreen) { XUngrabKeyboard(cimg::X11attr().display,CurrentTime); #ifdef cimg_use_xrandr if (cimg::X11attr().resolutions && cimg::X11attr().curr_resolution) { XRRScreenConfiguration *config = XRRGetScreenInfo(cimg::X11attr().display, DefaultRootWindow(cimg::X11attr().display)); XRRSetScreenConfig(cimg::X11attr().display, config, DefaultRootWindow(cimg::X11attr().display), 0, cimg::X11attr().curr_rotation, CurrentTime); XRRFreeScreenConfigInfo(config); XSync(cimg::X11attr().display, False); cimg::X11attr().curr_resolution = 0; } #endif if (background_window) XDestroyWindow(cimg::X11attr().display,background_window); background_window = 0; is_fullscreen = false; } } void _handle_events(const XEvent *const pevent) { XEvent event=*pevent; switch (event.type) { case ClientMessage: if ((int)event.xclient.message_type==(int)wm_delete_protocol && (int)event.xclient.data.l[0]==(int)wm_delete_window) { XUnmapWindow(cimg::X11attr().display,window); mouse_x = mouse_y = -1; std::memmove((void*)(buttons+1),(void*)buttons,255); std::memmove((void*)(keys+1),(void*)keys,255); if (key) { std::memmove((void*)(released_keys+1),(void*)released_keys,255); released_key = key; } key = button = 0; is_closed = is_event = true; } break; case ConfigureNotify: { while (XCheckWindowEvent(cimg::X11attr().display,window,StructureNotifyMask,&event)); const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height; const int nx = event.xconfigure.x, ny = event.xconfigure.y; if (nw && nh && (nw!=window_width || nh!=window_height)) { window_width = nw; window_height = nh; mouse_x = mouse_y = -1; XResizeWindow(cimg::X11attr().display,window,window_width,window_height); is_resized = is_event = true; } if (nx!=window_x || ny!=window_y) { window_x = nx; window_y = ny; is_moved = is_event = true; } } break; case Expose: { while (XCheckWindowEvent(cimg::X11attr().display,window,ExposureMask,&event)); _paint(false); if (is_fullscreen) { XWindowAttributes attr; XGetWindowAttributes(cimg::X11attr().display, window, &attr); while (attr.map_state != IsViewable) XSync(cimg::X11attr().display, False); XSetInputFocus(cimg::X11attr().display, window, RevertToParent, CurrentTime); } } break; case ButtonPress: { do { switch (event.xbutton.button) { case 1: std::memmove((void*)(buttons+1),(void*)buttons,255); button|=1; is_event = true; break; case 2: std::memmove((void*)(buttons+1),(void*)buttons,255); button|=4; is_event = true; break; case 3: std::memmove((void*)(buttons+1),(void*)buttons,255); button|=2; is_event = true; break; default: break; } } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonPressMask,&event)); } break; case ButtonRelease: { do { switch (event.xbutton.button) { case 1: std::memmove((void*)(buttons+1),(void*)buttons,255); button&=~1U; is_event = true; break; case 2: std::memmove((void*)(buttons+1),(void*)buttons,255); button&=~4U; is_event = true; break; case 3: std::memmove((void*)(buttons+1),(void*)buttons,255); button&=~2U; is_event = true; break; case 4: wheel++; is_event = true; break; case 5: wheel--; is_event = true; break; default: break; } } while (XCheckWindowEvent(cimg::X11attr().display,window,ButtonReleaseMask,&event)); } break; case KeyPress: { char tmp; KeySym ksym; XLookupString(&event.xkey,&tmp,1,&ksym,0); std::memmove((void*)(keys+1),(void*)keys,255); key = (unsigned int)ksym; std::memmove((void*)(released_keys+1),(void*)released_keys,255); released_key = 0; is_event = true; } break; case KeyRelease: { char tmp; KeySym ksym; XLookupString(&event.xkey,&tmp,1,&ksym,0); std::memmove((void*)(keys+1),(void*)keys,255); key = 0; std::memmove((void*)(released_keys+1),(void*)released_keys,255); released_key = (unsigned int)ksym; is_event = true; } break; case LeaveNotify: while (XCheckWindowEvent(cimg::X11attr().display,window,LeaveWindowMask,&event)); mouse_x = mouse_y =-1; is_event = true; break; case MotionNotify: while (XCheckWindowEvent(cimg::X11attr().display,window,PointerMotionMask,&event)); mouse_x = event.xmotion.x; mouse_y = event.xmotion.y; if (mouse_x<0 || mouse_y<0 || mouse_x>=dimx() || mouse_y>=dimy()) mouse_x = mouse_y = -1; is_event = true; break; } } static void* _events_thread(void *arg) { arg = 0; XEvent event; pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); for (;;) { pthread_mutex_lock(cimg::X11attr().mutex); for (unsigned int i=0; ievents)&3; const unsigned int emask = ((xevent_type>=1)?ExposureMask|StructureNotifyMask:0)| ((xevent_type>=2)?ButtonPressMask|KeyPressMask|PointerMotionMask|LeaveWindowMask:0)| ((xevent_type>=3)?ButtonReleaseMask|KeyReleaseMask:0); XSelectInput(cimg::X11attr().display,cimg::X11attr().wins[i]->window,emask); } bool event_flag = XCheckTypedEvent(cimg::X11attr().display, ClientMessage, &event); if (!event_flag) event_flag = XCheckMaskEvent(cimg::X11attr().display, ExposureMask|StructureNotifyMask|ButtonPressMask| KeyPressMask|PointerMotionMask|LeaveWindowMask|ButtonReleaseMask| KeyReleaseMask,&event); if (event_flag) { for (unsigned int i=0; iis_closed && event.xany.window==cimg::X11attr().wins[i]->window) cimg::X11attr().wins[i]->_handle_events(&event); } pthread_mutex_unlock(cimg::X11attr().mutex); pthread_testcancel(); cimg::sleep(7); } return 0; } // Windows-based display //----------------------- #elif cimg_display_type==2 CLIENTCREATESTRUCT ccs; BITMAPINFO bmi; unsigned int *data; DEVMODE curr_mode; HWND window; HWND background_window; HDC hdc; HANDLE thread; HANDLE created; HANDLE mutex; bool visible_cursor; static int screen_dimx() { DEVMODE mode; mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); return mode.dmPelsWidth; } static int screen_dimy() { DEVMODE mode; mode.dmSize = sizeof(DEVMODE); mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); return mode.dmPelsHeight; } CImgDisplay& assign() { if (!is_empty()) { DestroyWindow(window); if (events) TerminateThread(thread,0); if (data) delete[] data; if (title) delete[] title; if (is_fullscreen) _desinit_fullscreen(); width = height = normalization = events = 0; is_fullscreen = is_resized = is_moved = is_event = false; is_closed = true; title = 0; window_x = window_y = window_width = window_height = mouse_x = mouse_y = wheel = 0; std::memset((void*)buttons,0,256*sizeof(unsigned int)); std::memset((void*)keys,0,256*sizeof(unsigned int)); std::memset((void*)released_keys,0,256*sizeof(unsigned int)); min = max = 0; } return *this; } CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!dimw || !dimh) return assign(); _assign(dimw,dimh,title,normalization_type,events_type,fullscreen_flag,closed_flag); min = max = 0; std::memset(data,0,sizeof(unsigned int)*width*height); return paint(); } template CImgDisplay& assign(const CImg& img, const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!img) return assign(); CImg tmp; const CImg& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag); if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; } return display(nimg); } template CImgDisplay& assign(const CImgList& list,const char *title=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { if (!list) return assign(); CImg tmp; const CImg img = list.get_append('x','p'), &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); _assign(nimg.width,nimg.height,title,normalization_type,events_type,fullscreen_flag,closed_flag); if (normalization==2) { const CImgStats st(nimg,false); min = (float)st.min; max = (float)st.max; } return display(nimg); } CImgDisplay& assign(const CImgDisplay& win) { if (!win) return assign(); _assign(win.width,win.height,win.title,win.normalization,win.events,win.is_fullscreen,win.is_closed); std::memcpy(data,win.data,sizeof(unsigned int)*width*height); return paint(); } template CImgDisplay& display(const CImg& img) { if (is_empty()) return *this; return render(img).paint(); } CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { if (!nwidth || !nheight) return assign(); if (is_empty()) return assign(cimg::max(nwidth,0),cimg::max(nheight,0)); const unsigned int tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100), tmpdimy=(nheight>0)?nheight:(-nheight*height/100), dimx = cimg::min(tmpdimx?tmpdimx:1,(unsigned int)screen_dimx()), dimy = cimg::min(tmpdimy?tmpdimy:1,(unsigned int)screen_dimy()); const bool is_disp_different = (width!=dimx || height!=dimy), is_win_different = (window_width!=dimx || window_height!=dimy); if (is_disp_different || is_win_different) { RECT rect; rect.left=rect.top=0; rect.right = dimx-1; rect.bottom = dimy-1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int cwidth = rect.right-rect.left+1, cheight = rect.bottom-rect.top+1; SetWindowPos(window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); window_width = dimx; window_height = dimy; is_resized = false; if (is_disp_different) { unsigned int *ndata = new unsigned int[dimx*dimy]; if (redraw) _render_resize(data,width,height,ndata,dimx,dimy); else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); delete[] data; data = ndata; bmi.bmiHeader.biWidth = dimx; bmi.bmiHeader.biHeight = -(int)dimy; width = dimx; height = dimy; } if (is_fullscreen) move((screen_dimx()-width)/2,(screen_dimy()-height)/2); if (redraw) return paint(); } return *this; } CImgDisplay& move(const int posx,const int posy) { if (is_empty()) return *this; if (!is_fullscreen) { RECT rect; rect.left=rect.top=0; rect.right=window_width-1; rect.bottom=window_height-1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1; SetWindowPos(window,0,posx-border1,posy-border2,0,0,SWP_NOSIZE | SWP_NOZORDER); } else SetWindowPos(window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); window_x = posx; window_y = posy; is_moved = false; return show(); } CImgDisplay& set_mouse(const int posx, const int posy) { if (!is_closed && posx>=0 && posy>=0) { _update_window_pos(); SetCursorPos(window_x+posx,window_y+posy); mouse_x = posx; mouse_y = posy; } return *this; } CImgDisplay& hide_mouse() { if (is_empty()) return *this; visible_cursor = false; ShowCursor(FALSE); SendMessage(window,WM_SETCURSOR,0,0); return *this; } CImgDisplay& show_mouse() { if (is_empty()) return *this; visible_cursor = true; ShowCursor(TRUE); SendMessage(window,WM_SETCURSOR,0,0); return *this; } static void wait_all() { WaitForSingleObject(cimg::Win32attr().wait_event,INFINITE); } CImgDisplay& show() { if (is_empty()) return *this; if (is_closed) { is_closed = false; if (is_fullscreen) _init_fullscreen(); ShowWindow(window,SW_SHOW); _update_window_pos(); } return paint(); } CImgDisplay& close() { if (is_empty()) return *this; if (!is_closed && !is_fullscreen) { if (is_fullscreen) _desinit_fullscreen(); ShowWindow(window,SW_HIDE); is_closed = true; window_x = window_y = 0; } return *this; } CImgDisplay& set_title(const char *format,...) { if (is_empty()) return *this; char tmp[1024]={0}; va_list ap; va_start(ap, format); std::vsprintf(tmp,format,ap); va_end(ap); if (title) delete[] title; const int s = cimg::strlen(tmp)+1; title = new char[s]; std::memcpy(title,tmp,s*sizeof(char)); SetWindowTextA(window, tmp); return *this; } CImgDisplay& paint() { if (!is_closed) { WaitForSingleObject(mutex,INFINITE); SetDIBitsToDevice(hdc,0,0,width,height,0,0,0,height,data,&bmi,DIB_RGB_COLORS); ReleaseMutex(mutex); } return *this; } template CImgDisplay& render(const CImg& img) { if (is_empty()) return *this; if (!img) throw CImgArgumentException("CImgDisplay::_render_image() : Specified input image (%u,%u,%u,%u,%p) is empty.", img.width,img.height,img.depth,img.dim,img.data); if (img.depth!=1) return render(img.get_projections2d(img.width/2,img.height/2,img.depth/2)); const T *data1 = img.ptr(), *data2 = (img.dim>=2)?img.ptr(0,0,0,1):data1, *data3 = (img.dim>=3)?img.ptr(0,0,0,2):data1; WaitForSingleObject(mutex,INFINITE); unsigned int *const ndata = (img.width==width && img.height==height)?data:new unsigned int[img.width*img.height], *ptrd = ndata; if (!normalization || (normalization==3 && cimg::type::id()==cimg::type::id())) { min = max = 0; for (unsigned int xy = img.width*img.height; xy>0; xy--) *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | (unsigned char)*(data3++); } else { if (normalization==3) { if (cimg::type::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } else { min = (float)cimg::type::min(); max = (float)cimg::type::max(); } } else if ((min>max) || normalization==1) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } const float delta = max-min, mm = delta?delta:1.0f; for (unsigned int xy = img.width*img.height; xy>0; xy--) { const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm), G = (unsigned char)(255*(*(data2++)-min)/mm), B = (unsigned char)(255*(*(data3++)-min)/mm); *(ptrd++) = (R<<16) | (G<<8) | (B); } } if (ndata!=data) { _render_resize(ndata,img.width,img.height,data,width,height); delete[] ndata; } ReleaseMutex(mutex); return *this; } CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *ptitle=0, const unsigned int normalization_type=3, const unsigned int events_type=3, const bool fullscreen_flag=false, const bool closed_flag=false) { // Allocate space for window title const int s = cimg::strlen(ptitle)+1; char *tmp_title = s?new char[s]:0; if (s) std::memcpy(tmp_title,ptitle,s*sizeof(char)); // Destroy previous window if existing if (!is_empty()) assign(); // Set display variables width = cimg::min(dimw,(unsigned int)screen_dimx()); height = cimg::min(dimh,(unsigned int)screen_dimy()); normalization = normalization_type%4; events = events_type%4; is_fullscreen = fullscreen_flag; title = tmp_title; window_x = window_y = wheel = 0; mouse_x = mouse_y = -1; std::memset((void*)buttons,0,256*sizeof(unsigned int)); std::memset((void*)keys,0,256*sizeof(unsigned int)); std::memset((void*)released_keys,0,256*sizeof(unsigned int)); is_resized = is_moved = is_event = false; is_closed = closed_flag; fps_timer = fps_frames = timer = 0; fps_fps = 0; visible_cursor = true; if (is_fullscreen) _init_fullscreen(); // Create event thread void *arg = (void*)(new void*[2]); ((void**)arg)[0]=(void*)this; ((void**)arg)[1]=(void*)title; if (events) { unsigned long ThreadID = 0; mutex = CreateMutex(0,FALSE,0); created = CreateEvent(0,FALSE,FALSE,0); thread = CreateThread(0,0,_events_thread,arg,0,&ThreadID); WaitForSingleObject(created,INFINITE); } else _events_thread(arg); return *this; } static LRESULT APIENTRY _handle_events(HWND window,UINT msg,WPARAM wParam,LPARAM lParam) { #ifdef _WIN64 CImgDisplay* disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA); #else CImgDisplay* disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA); #endif MSG st_msg; switch(msg) { case WM_CLOSE: disp->mouse_x = disp->mouse_y = -1; disp->window_x = disp->window_y = 0; std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); std::memmove((void*)(disp->keys+1),(void*)disp->keys,255); if (disp->key) { std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,255); disp->released_key = disp->key; } disp->key = disp->button = 0; disp->is_closed=true; ReleaseMutex(disp->mutex); ShowWindow(disp->window,SW_HIDE); disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); return 0; case WM_SIZE: { while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)); WaitForSingleObject(disp->mutex,INFINITE); const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam); if (nw && nh && (nw!=disp->width || nh!=disp->height)) { disp->window_width = nw; disp->window_height = nh; disp->mouse_x = disp->mouse_y = -1; disp->is_resized = disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); } ReleaseMutex(disp->mutex); } break; case WM_MOVE: { while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)); WaitForSingleObject(disp->mutex,INFINITE); const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam)); if (nx!=disp->window_x || ny!=disp->window_y) { disp->window_x = nx; disp->window_y = ny; disp->is_moved = disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); } ReleaseMutex(disp->mutex); } break; case WM_PAINT: disp->paint(); break; } if (disp->events>=2) switch(msg) { case WM_KEYDOWN: std::memmove((void*)(disp->keys+1),(void*)disp->keys,255); disp->key = (int)wParam; std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,255); disp->released_key = 0; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_MOUSEMOVE: { while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)); disp->mouse_x = LOWORD(lParam); disp->mouse_y = HIWORD(lParam); if (disp->mouse_x<0 || disp->mouse_y<0 || disp->mouse_x>=disp->dimx() || disp->mouse_y>=disp->dimy()) disp->mouse_x=disp->mouse_y=-1; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); } break; case WM_LBUTTONDOWN: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button|=1U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_RBUTTONDOWN: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button|=2U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_MBUTTONDOWN: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button|=4U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case 0x020A: // WM_MOUSEWHEEL: disp->wheel+=(int)((short)HIWORD(wParam))/120; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); } if (disp->events>=3) switch(msg) { case WM_KEYUP: std::memmove((void*)(disp->keys+1),(void*)disp->keys,255); disp->key = 0; std::memmove((void*)(disp->released_keys+1),(void*)disp->released_keys,255); disp->released_key = (int)wParam; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_LBUTTONUP: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button&=~1U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_RBUTTONUP: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button&=~2U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_MBUTTONUP: std::memmove((void*)(disp->buttons+1),(void*)disp->buttons,255); disp->button&=~4U; disp->is_event = true; SetEvent(cimg::Win32attr().wait_event); break; case WM_SETCURSOR: if (disp->visible_cursor) ShowCursor(TRUE); else ShowCursor(FALSE); break; } return DefWindowProc(window,msg,wParam,lParam); } static DWORD WINAPI _events_thread(void* arg) { CImgDisplay *disp = (CImgDisplay*)(((void**)arg)[0]); const char *title = (const char*)(((void**)arg)[1]); MSG msg; delete[] (void**)arg; disp->bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); disp->bmi.bmiHeader.biWidth=disp->width; disp->bmi.bmiHeader.biHeight=-(int)disp->height; disp->bmi.bmiHeader.biPlanes=1; disp->bmi.bmiHeader.biBitCount=32; disp->bmi.bmiHeader.biCompression=BI_RGB; disp->bmi.bmiHeader.biSizeImage=0; disp->bmi.bmiHeader.biXPelsPerMeter=1; disp->bmi.bmiHeader.biYPelsPerMeter=1; disp->bmi.bmiHeader.biClrUsed=0; disp->bmi.bmiHeader.biClrImportant=0; disp->data = new unsigned int[disp->width*disp->height]; if (!disp->is_fullscreen) { // Normal window RECT rect; rect.left=rect.top=0; rect.right=disp->width-1; rect.bottom=disp->height-1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (rect.right-rect.left+1-disp->width)/2, border2 = rect.bottom-rect.top+1-disp->height-border1; disp->window = CreateWindowA("MDICLIENT",title?title:" ", WS_OVERLAPPEDWINDOW | (disp->is_closed?0:WS_VISIBLE), CW_USEDEFAULT,CW_USEDEFAULT, disp->width + 2*border1, disp->height + border1 + border2, 0,0,0,&(disp->ccs)); if (!disp->is_closed) { GetWindowRect(disp->window,&rect); disp->window_x = rect.left + border1; disp->window_y = rect.top + border2; } else disp->window_x = disp->window_y = 0; } else { // Fullscreen window const unsigned int sx = screen_dimx(), sy = screen_dimy(); disp->window = CreateWindowA("MDICLIENT",title?title:" ", WS_POPUP | (disp->is_closed?0:WS_VISIBLE), (sx-disp->width)/2, (sy-disp->height)/2, disp->width,disp->height,0,0,0,&(disp->ccs)); disp->window_x = disp->window_y = 0; } SetForegroundWindow(disp->window); disp->hdc = GetDC(disp->window); disp->window_width = disp->width; disp->window_height = disp->height; disp->mouse_x = disp->mouse_y = -1; disp->wheel = 0; std::memset((void*)disp->buttons,0,256*sizeof(unsigned int)); std::memset((void*)disp->keys,0,256*sizeof(unsigned int)); std::memset((void*)disp->released_keys,0,256*sizeof(unsigned int)); disp->is_resized = disp->is_moved = disp->is_event = false; if (disp->events) { #ifdef _WIN64 SetWindowLongPtr(disp->window,GWLP_USERDATA,(LONG_PTR)disp); SetWindowLongPtr(disp->window,GWLP_WNDPROC,(LONG_PTR)_handle_events); #else SetWindowLong(disp->window,GWL_USERDATA,(LONG)disp); SetWindowLong(disp->window,GWL_WNDPROC,(LONG)_handle_events); #endif SetEvent(disp->created); while( GetMessage(&msg,0,0,0) ) DispatchMessage( &msg ); } return 0; } void _init_fullscreen() { background_window = 0; if (is_fullscreen && !is_closed) { DEVMODE mode; unsigned int imode=0, ibest=0, bestbpp=0, bw=~0U, bh=~0U; for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); imode++) { const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight; if (nw>=width && nh>=height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) { bestbpp = mode.dmBitsPerPel; ibest = imode; bw = nw; bh = nh; } } if (bestbpp) { curr_mode.dmSize = sizeof(DEVMODE); curr_mode.dmDriverExtra = 0; EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&curr_mode); EnumDisplaySettings(0,ibest,&mode); ChangeDisplaySettings(&mode,0); } else curr_mode.dmSize = 0; const unsigned int sx = screen_dimx(), sy = screen_dimy(); if (sx!=width || sy!=height) { CLIENTCREATESTRUCT background_ccs; background_window = CreateWindowA("MDICLIENT"," ",WS_POPUP | WS_VISIBLE, 0,0,sx,sy,0,0,0,&background_ccs); SetForegroundWindow(background_window); } } else curr_mode.dmSize = 0; } void _desinit_fullscreen() { if (is_fullscreen) { if (background_window) DestroyWindow(background_window); background_window = 0; if (curr_mode.dmSize) ChangeDisplaySettings(&curr_mode,0); is_fullscreen = false; } } CImgDisplay& _update_window_pos() { if (!is_closed) { RECT rect; rect.left = rect.top = 0; rect.right = width-1; rect.bottom = height-1; AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); const int border1 = (rect.right-rect.left+1-width)/2, border2 = rect.bottom-rect.top+1-height-border1; GetWindowRect(window,&rect); window_x = rect.left + border1; window_y = rect.top + border2; } else window_x = window_y = -1; return *this; } #endif }; /* #-------------------------------------- # # # # Definition of the CImg structure # # # #-------------------------------------- */ //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T. /** This is the main class of the %CImg Library. It declares and constructs an image, allows access to its pixel values, and is able to perform various image operations. \par Image representation A %CImg image is defined as an instance of the container \ref CImg, which contains a regular grid of pixels, each pixel value being of type \c T. The image grid can have up to 4 dimensions : width, height, depth and number of channels. Usually, the three first dimensions are used to describe spatial coordinates (x,y,z), while the number of channels is rather used as a vector-valued dimension (it may describe the R,G,B color channels for instance). If you need a fifth dimension, you can use image lists \ref CImgList rather than simple images \ref CImg. Thus, the \ref CImg class is able to represent volumetric images of vector-valued pixels, as well as images with less dimensions (1D scalar signal, 2D color images, ...). Most member functions of the class CImg are designed to handle this maximum case of (3+1) dimensions. Concerning the pixel value type \c T : fully supported template types are the basic C++ types : unsigned char, char, short, unsigned int, int, unsigned long, long, float, double, ... . Typically, fast image display can be done using CImg images, while complex image processing algorithms may be rather coded using CImg or CImg images that have floating-point pixel values. The default value for the template T is \c float. Using your own template types may be possible. However, you will certainly have to define the complete set of arithmetic and logical operators for your class. \par Image structure The \ref CImg<\c T> structure contains \a five fields : - \ref width defines the number of \a columns of the image (size along the X-axis). - \ref height defines the number of \a rows of the image (size along the Y-axis). - \ref depth defines the number of \a slices of the image (size along the Z-axis). - \ref dim defines the number of \a channels of the image (size along the V-axis). - \ref data defines a \a pointer to the \a pixel \a data (of type \c T). You can access these fields publicly although it is recommended to use the dedicated functions dimx(), dimy(), dimz(), dimv() and ptr() to do so. Image dimensions are not limited to a specific range (as long as you got enough available memory). A value of \e 1 usually means that the corresponding dimension is \a flat. If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty. Empty images should not contain any pixel data and thus, will not be processed by CImg member functions (a CImgInstanceException will be thrown instead). Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage). \par Image declaration and construction Declaring an image can be done by using one of the several available constructors. Here is a list of the most used : - Construct images from arbitrary dimensions : - CImg img; declares an empty image. - CImg img(128,128); declares a 128x128 greyscale image with \c unsigned \c char pixel values. - CImg img(3,3); declares a 3x3 matrix with \c double coefficients. - CImg img(256,256,1,3); declares a 256x256x1x3 (color) image (colors are stored as an image with three channels). - CImg img(128,128,128); declares a 128x128x128 volumetric and greyscale image (with \c double pixel values). - CImg<> img(128,128,128,3); declares a 128x128x128 volumetric color image (with \c float pixels, which is the default value of the template parameter \c T). - \b Note : images pixels are not automatically initialized to 0. You may use the function \ref fill() to do it, or use the specific constructor taking 5 parameters like this : CImg<> img(128,128,128,3,0); declares a 128x128x128 volumetric color image with all pixel values to 0. - Construct images from filenames : - CImg img("image.jpg"); reads a JPEG color image from the file "image.jpg". - CImg img("analyze.hdr"); reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr". - \b Note : You need to install ImageMagick to be able to read common compressed image formats (JPG,PNG,...) (See \ref cimg_files_io). - Construct images from C-style arrays : - CImg img(data_buffer,256,256); constructs a 256x256 greyscale image from a \c int* buffer \c data_buffer (of size 256x256=65536). - CImg img(data_buffer,256,256,1,3,false); constructs a 256x256 color image from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). - CImg img(data_buffer,256,256,1,3,true); constructs a 256x256 color image from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels are multiplexed). The complete list of constructors can be found here. \par Most useful functions The \ref CImg class contains a lot of functions that operates on images. Some of the most useful are : - operator()(), operator[]() : allows to access or write pixel values. - display() : displays the image in a new window. \sa CImgList, CImgStats, CImgDisplay, CImgException. **/ template struct CImg { //! Variable representing the width of the instance image (i.e. dimensions along the X-axis). /** \remark - Prefer using the function CImg::dimx() to get information about the width of an image. - Use function CImg::resize() to set a new width for an image. Setting directly the variable \c width would probably result in a library crash. - Empty images have \c width defined to \c 0. **/ unsigned int width; //! Variable representing the height of the instance image (i.e. dimensions along the Y-axis). /** \remark - Prefer using the function CImg::dimy() to get information about the height of an image. - Use function CImg::resize() to set a new height for an image. Setting directly the variable \c height would probably result in a library crash. - 1D signals have \c height defined to \c 1. - Empty images have \c height defined to \c 0. **/ unsigned int height; //! Variable representing the depth of the instance image (i.e. dimensions along the Z-axis). /** \remark - Prefer using the function CImg::dimz() to get information about the depth of an image. - Use function CImg::resize() to set a new depth for an image. Setting directly the variable \c depth would probably result in a library crash. - Classical 2D images have \c depth defined to \c 1. - Empty images have \c depth defined to \c 0. **/ unsigned int depth; //! Variable representing the number of channels of the instance image (i.e. dimensions along the V-axis). /** \remark - Prefer using the function CImg::dimv() to get information about the depth of an image. - Use function CImg::resize() to set a new vector dimension for an image. Setting directly the variable \c dim would probably result in a library crash. - Scalar-valued images (one value per pixel) have \c dim defined to \c 1. - Empty images have \c depth defined to \c 0. **/ unsigned int dim; //! Variable telling if pixel buffer of the instance image is shared with another one. bool is_shared; //! Pointer to the first pixel of the pixel buffer. T *data; //! Iterator type for CImg. /** \remark - An \p iterator is a T* pointer (address of a pixel value in the pixel buffer). - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL. **/ typedef T* iterator; //! Const iterator type for CImg. /** \remark - A \p const_iterator is a const T* pointer (address of a pixel value in the pixel buffer). - Iterators are not directly used in %CImg functions, they have been introduced for compatibility with the STL. **/ typedef const T* const_iterator; //! Get value type typedef T value_type; //@} //--------------------------- // //! \name Plugins //@{ //--------------------------- #ifdef cimg_plugin #include cimg_plugin #endif //@} //-------------------------------------- // //! \name Constructors-Destructor-Copy //@{ //-------------------------------------- //! Default constructor. /** The default constructor creates an empty instance image. \remark - An empty image does not contain any data and has all of its dimensions \ref width, \ref height, \ref depth, \ref dim set to 0 as well as its pointer to the pixel buffer \ref data. - An empty image is non-shared. \see ~CImg(), assign(), is_empty(). **/ CImg(): width(0),height(0),depth(0),dim(0),is_shared(false),data(0) {} //! Destructor. /** The destructor destroys the instance image. \remark - Destructing an empty or shared image does nothing. - Otherwise, all memory used to store the pixel data of the instance image is freed. - When destroying a non-shared image, be sure that every shared instances of the same image are also destroyed to avoid further access to desallocated memory buffers. \see CImg(), assign(), is_empty(). **/ ~CImg() { if (data && !is_shared) delete[] data; } //! In-place version of the default constructor. /** This function replaces the instance image by an empty image. \remark - Memory used by the previous content of the instance image is freed if necessary. - If the instance image was initially shared, it is replaced by a (non-shared) empty image. - This function is useful to free memory used by an image that is not of use, but which has been created in the current code scope (i.e. not destroyed yet). \see ~CImg(), assign(), is_empty(). **/ CImg& assign() { if (data && !is_shared) delete[] data; width = height = depth = dim = 0; is_shared = false; data = 0; return *this; } //! In-place version of the default constructor. /** This function is strictly equivalent to \ref assign() and has been introduced for having a STL-compliant function name. \see assign(). **/ CImg& clear() { return assign(); } //! Default copy constructor. /** The default copy constructor creates a new instance image having same dimensions (\ref width, \ref height, \ref depth, \ref dim) and same pixel values as the input image \p img. \param img The input image to copy. \remark - If the input image \p img is non-shared or have a different template type \p t != \p T, the default copy constructor allocates a new pixel buffer and copy the pixel data of \p img into it. In this case, the pointers \ref data to the pixel buffers of the two images are different and the resulting instance image is non-shared. - If the input image \p img is shared and has the same template type \p t == \p T, the default copy constructor does not allocate a new pixel buffer and the resulting instance image shares its pixel buffer with the input image \p img, which means that modifying pixels of \p img also modifies the created instance image. - Copying an image having a different template type \p t != \p T performs a crude static cast conversion of each pixel value from type \p t to type \p T. - Copying an image having the same template type \p t == \p T is significantly faster. \see assign(const CImg< t >&), CImg(const CImg< t >&,const bool). **/ template CImg(const CImg& img):is_shared(false) { const unsigned int siz = img.size(); if (img.data && siz) { width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz]; const t *ptrs = img.data+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); } else { width = height = depth = dim = 0; data = 0; } } CImg(const CImg& img) { const unsigned int siz = img.size(); if (img.data && siz) { width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = img.is_shared; if (is_shared) data = const_cast(img.data); else { data = new T[siz]; std::memcpy(data,img.data,siz*sizeof(T)); } } else { width = height = depth = dim = 0; is_shared = false; data = 0; } } //! In-place version of the default copy constructor. /** This function assigns a copy of the input image \p img to the current instance image. \param img The input image to copy. \remark - If the instance image is not shared, the content of the input image \p img is copied into a new buffer becoming the new pixel buffer of the instance image, while the old pixel buffer is freed if necessary. - If the instance image is shared, the content of the input image \p img is copied into the current (shared) pixel buffer of the instance image, modifying then the image referenced by the shared instance image. The instance image still remains shared. \see CImg(const CImg< t >&), operator=(const CImg< t >&). **/ template CImg& assign(const CImg& img) { return assign(img.data,img.width,img.height,img.depth,img.dim); } //! Advanced copy constructor. /** The advanced copy constructor - as the default constructor CImg(const CImg< t >&) - creates a new instance image having same dimensions \ref width, \ref height, \ref depth, \ref dim and same pixel values as the input image \p img. But it also decides if the created instance image shares its memory with the input image \p img (if the input parameter \p shared is set to \p true) or not (if the input parameter \p shared is set to \p false). \param img The input image to copy. \param shared Boolean flag that decides if the copy is shared on non-shared. \remark - 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. - If a non-shared copy of the input image \p img is created, a new memory buffer is allocated for pixel data. - If a shared copy of the input image \p img is created, no extra memory is allocated and the pixel buffer of the instance image is the same as the one used by the input image \p img. \see CImg(const CImg< t >&), assign(const CImg< t >&,const bool). **/ template CImg(const CImg& img, const bool shared):is_shared(false) { if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared copy from a CImg<%s> image " "(different pixel types).",pixel_type(),CImg::pixel_type()); const unsigned int siz = img.size(); if (img.data && siz) { width = img.width; height = img.height; depth = img.depth; dim = img.dim; data = new T[siz]; const t *ptrs = img.data+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); } else { width = height = depth = dim = 0; data = 0; } } CImg(const CImg& img, const bool shared) { const unsigned int siz = img.size(); if (img.data && siz) { width = img.width; height = img.height; depth = img.depth; dim = img.dim; is_shared = shared; if (is_shared) data = const_cast(img.data); else { data = new T[siz]; std::memcpy(data,img.data,siz*sizeof(T)); } } else { width = height = depth = dim = 0; is_shared = false; data = 0; } } //! In-place version of the advanced constructor. /** This function - as the simpler function assign(const CImg< t >&) - assigns a copy of the input image \p img to the current instance image. But it also decides if the copy is shared (if the input parameter \p shared is set to \true) or non-shared (if the input parameter \p shared is set to false). \param img The input image to copy. \param shared Boolean flag that decides if the copy is shared or non-shared. \remark - 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. - If a non-shared copy of the input image \p img is assigned, a new memory buffer is allocated for pixel data. - If a shared copy of the input image \p img is assigned, no extra memory is allocated and the pixel buffer of the instance image is the same as the one used by the input image \p img. \see CImg(const CImg< t >&,const bool), assign(const CImg< t >&). **/ template CImg& assign(const CImg& img, const bool shared) { return assign(img.data,img.width,img.height,img.depth,img.dim,shared); } //! Constructs a new image with given size (\p dx,\p dy,\p dz,\p dv). /** This constructors create an instance image of size (\p dx,\p dy,\p dz,\p dv) with pixels of type \p T. \param dx Desired size along the X-axis, i.e. the \ref width of the image. \param dy Desired size along the Y-axis, i.e. the \ref height of the image. \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. \param dv Desired size along the V-axis, i.e. the number of image channels \ref dim. \remark - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the created image is empty and all has its dimensions set to 0. No memory for pixel data is then allocated. - This constructor creates only non-shared images. - Image pixels allocated by this constructor are \b not \b initialized. Use the constructor CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&) to get an image of desired size with pixels set to a particular value. \see assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int), CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&). **/ explicit CImg(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1): is_shared(false) { const unsigned int siz = dx*dy*dz*dv; if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; } else { width = height = depth = dim = 0; data = 0; } } //! In-place version of the previous constructor. /** 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. \param dx Desired size along the X-axis, i.e. the \ref width of the image. \param dy Desired size along the Y-axis, i.e. the \ref height of the image. \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. \param dv Desired size along the V-axis, i.e. the number of image channels \p dim. - If one of the input dimension \p dx,\p dy,\p dz or \p dv is set to 0, the instance image becomes empty and all has its dimensions set to 0. No memory for pixel data is then allocated. - Memory buffer used to store previous pixel values is freed if necessary. - If the instance image is shared, this constructor actually does nothing more than verifying that new and old image dimensions fit. - Image pixels allocated by this function are \b not \b initialized. Use the function assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int,const T&) to assign an image of desired size with pixels set to a particular value. \see CImg(), assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int). **/ CImg& assign(const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) { const unsigned long siz = dx*dy*dz*dv, curr_siz = size(); if (is_shared) { if (siz!=curr_siz) throw CImgArgumentException("CImg<%s>::assign() : Cannot assign image (%u,%u,%u,%u) to shared instance image (%u,%u,%u,%u,%p).", pixel_type(),dx,dy,dz,dv,width,height,depth,dim,data); } else { if (siz) { if (siz!=curr_siz) { if (data) delete[] data; data = new T[siz]; } width = dx; height = dy; depth = dz; dim = dv; } else { if (data) delete[] data; width = height = depth = dim = 0; data = 0; } } return *this; } //! Construct an image with given size (\p dx,\p dy,\p dz,\p dv) and with pixel having a default value \p val. /** 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 values of the created instance image to \p val. \param dx Desired size along the X-axis, i.e. the \ref width of the image. \param dy Desired size along the Y-axis, i.e. the \ref height of the image. \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. \param dv Desired size along the V-axis, i.e. the number of image channels \p dim. \param val Default value for image pixels. \remark - This constructor has the same properties as CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int). \see CImg(const unsigned int,const unsigned int,const unsigned int,const unsigned int). **/ CImg(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T& val): is_shared(false) { const unsigned int siz = dx*dy*dz*dv; if (siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; fill(val); } else { width = height = depth = dim = 0; data = 0; } } //! In-place version of the previous constructor. /** 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 and sets all pixel values of the instance image to \p val. \param dx Desired size along the X-axis, i.e. the \ref width of the image. \param dy Desired size along the Y-axis, i.e. the \ref height of the image. \param dz Desired size along the Z-axis, i.e. the \ref depth of the image. \param dv Desired size along the V-axis, i.e. the number of image channels \p dim. \param val Default value for image pixels. \remark - This function has the same properties as assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int). \see assign(const unsigned int,const unsigned int,const unsigned int,const unsigned int). **/ CImg& assign(const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const T& val) { return assign(dx,dy,dz,dv).fill(val); } //! Construct an image from an image file. /** This constructor creates an instance image by reading it from a file. \param filename Filename of the image file. \remark - The image format is deduced from the filename only by looking for the filename extension i.e. without analyzing the file itself. - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with. More informations on this topic can be found in cimg_files_io. - If the filename is not found, a CImgIOException is thrown by this constructor. \see assign(const char *const), load(const char *const) **/ CImg(const char *const filename):width(0),height(0),depth(0),dim(0),is_shared(false),data(0) { assign(filename); } //! In-place version of the previous constructor. /** This function replaces the instance image by the one that have been read from the given file. \param filename Filename of the image file. - The image format is deduced from the filename only by looking for the filename extension i.e. without analyzing the file itself. - Recognized image formats depend on the tools installed on your system or the external libraries you use to link your code with. More informations on this topic can be found in cimg_files_io. - If the filename is not found, a CImgIOException is thrown by this constructor. **/ CImg& assign(const char *const filename) { return load(filename); } //! Construct an image from raw memory buffer. /** This constructor creates an instance image of size (\p dx,\p dy,\p dz,\p dv) and fill its pixel buffer by copying data values from the input raw pixel buffer \p data_buffer. **/ template CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1, const bool shared=false):is_shared(false) { if (shared) throw CImgArgumentException("CImg<%s>::CImg() : Cannot construct a shared copy from a (%s*) buffer " "(different pixel types).",pixel_type(),CImg::pixel_type()); const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); } else { width = height = depth = dim = 0; data = 0; } } #ifdef cimg_use_visualcpp6 CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const bool shared) { #else CImg(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1, const bool shared=false) { #endif const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) { width = dx; height = dy; depth = dz; dim = dv; is_shared = shared; if (is_shared) data = const_cast(data_buffer); else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); } } else { width = height = depth = dim = 0; is_shared = false; data = 0; } } //! In-place version of the previous constructor. #ifdef cimg_use_visualcpp6 template CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv) { #else template CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) { #endif assign(dx,dy,dz,dv); const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) { const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); } else { width = height = depth = dim = 0; is_shared = false; data = 0; } return *this; } CImg& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1, const unsigned int dv=1) { assign(dx,dy,dz,dv); const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) std::memcpy(data,data_buffer,siz*sizeof(T)); else { width = height = depth = dim = 0; is_shared = false; data = 0; } return *this; } //! In-place version of the previous constructor, allowing to force the shared state of the instance image. template CImg& assign(const t *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const bool shared) { if (shared) throw CImgArgumentException("CImg<%s>::assign() : Cannot define a shared copy from a CImg<%s> image " "(different pixel types).",pixel_type(),CImg::pixel_type()); if (data && !is_shared) delete[] data; is_shared = false; const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) { width = dx; height = dy; depth = dz; dim = dv; data = new T[siz]; const t *ptrs = data_buffer+siz; cimg_for(*this,ptrd,T) *ptrd = (T)*(--ptrs); } else { width = height = depth = dim = 0; data = 0; } return *this; } CImg& assign(const T *const data_buffer, const unsigned int dx, const unsigned int dy, const unsigned int dz, const unsigned int dv, const bool shared) { if (data && !is_shared) delete[] data; const unsigned int siz = dx*dy*dz*dv; if (data_buffer && siz) { width = dx; height = dy; depth = dz; dim = dv; is_shared = shared; if (is_shared) data = const_cast(data_buffer); else { data = new T[siz]; std::memcpy(data,data_buffer,siz*sizeof(T)); } } else { width = height = depth = dim = 0; is_shared = false; data = 0; } return *this; } // INNER ROUTINE : Swap fields of an image (use it carefully!) // If one of the image is shared, its content is replaced by the non-shared image (which remains unchanged). CImg& swap(CImg& img) { if (img.is_shared==is_shared) { cimg::swap(width,img.width); cimg::swap(height,img.height); cimg::swap(depth,img.depth); cimg::swap(dim,img.dim); cimg::swap(data,img.data); } else { if (img.is_shared) img.assign(*this); else assign(img); } return img; } //@} //------------------------------------- // //! \name Image Informations //@{ //------------------------------------- //! Return the type of the pixel values. /** \return a string describing the type of the image pixels (template parameter \p T). - The string returned may contains spaces ("unsigned char"). - If the template parameter T does not correspond to a registered type, the string "unknown" is returned. **/ static const char* pixel_type() { return cimg::type::id(); } //! Return the total number of pixel values in an image. /** - Equivalent to : dimx() * dimy() * dimz() * dimv(). \par example: \code CImg<> img(100,100,1,3); if (img.size()==100*100*3) std::fprintf(stderr,"This statement is true"); \endcode \sa dimx(), dimy(), dimz(), dimv() **/ unsigned long size() const { return width*height*depth*dim; } //! Return the number of columns of the instance image (size along the X-axis, i.e image width). /** \sa width, dimy(), dimz(), dimv(), size(). **/ int dimx() const { return (int)width; } //! Return the number of rows of the instance image (size along the Y-axis, i.e image height). /** \sa height, dimx(), dimz(), dimv(), size(). **/ int dimy() const { return (int)height; } //! Return the number of slices of the instance image (size along the Z-axis). /** \sa depth, dimx(), dimy(), dimv(), size(). **/ int dimz() const { return (int)depth; } //! Return the number of vector channels of the instance image (size along the V-axis). /** \sa dim, dimx(), dimy(), dimz(), size(). **/ int dimv() const { return (int)dim; } //! Return \c true if images \c (*this) and \c img have same width. template bool is_sameX(const CImg& img) const { return (width==img.width); } //! Return \c true if images \c (*this) and the display \c disp have same width. bool is_sameX(const CImgDisplay& disp) const { return (width==disp.width); } //! Return \c true if images \c (*this) and \c img have same height. template bool is_sameY(const CImg& img) const { return (height==img.height); } //! Return \c true if images \c (*this) and the display \c disp have same height. bool is_sameY(const CImgDisplay& disp) const { return (height==disp.height); } //! Return \c true if images \c (*this) and \c img have same depth. template bool is_sameZ(const CImg& img) const { return (depth==img.depth); } //! Return \c true if images \c (*this) and \c img have same dim. template bool is_sameV(const CImg& img) const { return (dim==img.dim); } //! Return \c true if images have same width and same height. template bool is_sameXY(const CImg& img) const { return (is_sameX(img) && is_sameY(img)); } //! Return \c true if image \c (*this) and the display \c disp have same width and same height. bool is_sameXY(const CImgDisplay& disp) const { return (is_sameX(disp) && is_sameY(disp)); } //! Return \c true if images have same width, same height and same depth. template bool is_sameXYZ(const CImg& img) const { return (is_sameXY(img) && is_sameZ(img)); } //! Return \c true if images \c (*this) and \c img have same width, same height, same depth and same number of channels. template bool is_sameXYZV(const CImg& img) const { return (is_sameXYZ(img) && is_sameV(img)); } //! Return \c true if pixel (x,y,z,v) is inside the image boundaries. bool contains(const int x, const int y=0, const int z=0, const int v=0) const { return data && x>=0 && x<(int)width && y>=0 && y<(int)height && z>=0 && z<(int)depth && v>=0 && v<(int)dim; } //! Return \c true if current image is empty. bool is_empty() const { return !(data && width && height && depth && dim); } //! Image to boolean conversion operator bool() const { return !is_empty(); } //! Return the offset of the pixel coordinates (\p x,\p y,\p z,\p v) with respect to the data pointer \c data. /** \param x X-coordinate of the pixel. \param y Y-coordinate of the pixel. \param z Z-coordinate of the pixel. \param v V-coordinate of the pixel. - No checking is done on the validity of the given coordinates. \par example: \code CImg img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10). float val = img[off]; // Get the blue value of the pixel. \endcode \sa ptr(), operator()(), operator[](), cimg_storage. **/ long offset(const int x=0, const int y=0, const int z=0, const int v=0) const { return x + y*width + z*width*height + v*width*height*depth; } //! Return a pointer to the pixel value located at (\p x,\p y,\p z,\p v). /** \param x X-coordinate of the pixel. \param y Y-coordinate of the pixel. \param z Z-coordinate of the pixel. \param v V-coordinate of the pixel. - When called without parameters, ptr() returns a pointer to the begining of the pixel buffer. - If the macro \c cimg_debug == 3, boundary checking is performed and warning messages may appear if given coordinates are outside the image range (but function performances decrease). \par example: \code CImg img(100,100,1,1,0); // Define a 100x100 greyscale image with float-valued pixels. float *ptr = ptr(10,10); // Get a pointer to the pixel located at (10,10). float val = *ptr; // Get the pixel value. \endcode \sa data, offset(), operator()(), operator[](), cimg_storage, cimg_environment. **/ T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) { const long off = offset(x,y,z,v); #if cimg_debug>=3 if (off<0 || off>=(long)size()) { cimg::warn(true,"CImg<%s>::ptr() : Asked for a pointer at coordinates (%u,%u,%u,%u) (offset=%u), " "outside image range (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return data; } #endif return data+off; } const T* ptr(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const { const long off = offset(x,y,z,v); #if cimg_debug>=3 if (off<0 || off>=(long)size()) { cimg::warn(true,"CImg<%s>::ptr() : Trying to get a pointer at (%u,%u,%u,%u) (offset=%u) which is" "outside the data of the image (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return data; } #endif return data+off; } //! Return an iterator to the first image pixel iterator begin() { return data; } const_iterator begin() const { return data; } //! Return an iterator to the last image pixel iterator end() { return data + size(); } const_iterator end() const { return data + size(); } //! Fast access to pixel value for reading or writing. /** \param x X-coordinate of the pixel. \param y Y-coordinate of the pixel. \param z Z-coordinate of the pixel. \param v V-coordinate of the pixel. - If one image dimension is equal to 1, it can be omitted in the coordinate list (see example below). - If the macro \c cimg_debug == 3, boundary checking is performed and warning messages may appear (but function performances decrease). \par example: \code CImg img(100,100,1,3,0); // Define a 100x100 color image with float-valued black pixels. const float valR = img(10,10,0,0); // Read the red component at coordinates (10,10). const float valG = img(10,10,0,1); // Read the green component at coordinates (10,10) const float valB = img(10,10,2); // Read the blue component at coordinates (10,10) (Z-coordinate omitted here). const float avg = (valR + valG + valB)/3; // Compute average pixel value. img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the pixel (10,10) by the average grey value. \endcode \sa operator[](), ptr(), offset(), cimg_storage, cimg_environment. **/ T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) { const long off = offset(x,y,z,v); #if cimg_debug>=3 if (!data || off>=(long)size()) { cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) " "outside the image range (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return *data; } #endif return data[off]; } const T& operator()(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const { const long off = offset(x,y,z,v); #if cimg_debug>=3 if (!data || off>=(long)size()) { cimg::warn(true,"CImg<%s>::operator() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) " "outside the image range (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return *data; } #endif return data[off]; } //! Return pixel value at a given position. Equivalent to operator(). T& at(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) { const long off = offset(x,y,z,v); if (!data || off>=(long)size()) throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) " "outside the image range (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return data[off]; } const T& at(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const { const long off = offset(x,y,z,v); if (!data || off>=(long)size()) throw CImgArgumentException("CImg<%s>::at() : Pixel access requested at (%u,%u,%u,%u) (offset=%u) " "outside the image range (%u,%u,%u,%u) (size=%u)", pixel_type(),x,y,z,v,off,width,height,depth,dim,size()); return data[off]; } //! Fast access to pixel value for reading or writing, using an offset to the image pixel. /** \param off Offset of the pixel according to the begining of the pixel buffer, given by ptr(). - If the macro \c cimg_debug==3, boundary checking is performed and warning messages may appear (but function performances decrease). - As pixel values are aligned in memory, this operator can sometime useful to access values easier than with operator()() (see example below). \par example: \code CImg vec(1,10); // Define a vector of float values (10 lines, 1 row). const float val1 = vec(0,4); // Get the fifth element using operator()(). const float val2 = vec[4]; // Get the fifth element using operator[]. Here, val2==val1. \endcode \sa operator()(), ptr(), offset(), cimg_storage, cimg_environment. **/ T& operator[](const unsigned long off) { return operator()(off); } const T& operator[](const unsigned long off) const { return operator()(off); } //! Return a reference to the last image value T& back() { return operator()(size()-1); } const T& back() const { return operator()(size()-1); } //! Return a reference to the first image value T& front() { return *data; } const T& front() const { return *data; } //! Read a pixel value with Dirichlet or Neumann boundary conditions. /** \param x X-coordinate of the pixel. \param y Y-coordinate of the pixel. \param z Z-coordinate of the pixel. \param v V-coordinate of the pixel. \param out_val Desired value if pixel coordinates are outside the image range (optional parameter). - This function allows to read pixel values with boundary checking on all coordinates. - If given coordinates are outside the image range and the parameter out_val is specified, the value \c out_val is returned. - If given coordinates are outside the image range and the parameter out_val is not specified, the closest pixel value is returned. \par example: \code CImg img(100,100,1,1,128); // Define a 100x100 images with all pixel values equal to 128. const float val1 = img.pix4d(10,10,0,0,0); // Equivalent to val1=img(10,10) (but slower). const float val2 = img.pix4d(-4,5,0,0,0); // Return 0, since coordinates are outside the image range. const float val3 = img.pix4d(10,10,5,0,64); // Return 64, since coordinates are outside the image range. \endcode \sa operator()(), linear_pix4d(), cubic_pix2d(). **/ T pix4d(const int x, const int y, const int z, const int v, const T& out_val) const { return (x<0 || y<0 || z<0 || v<0 || x>=dimx() || y>=dimy() || z>=dimz() || v>=dimv())?out_val:(*this)(x,y,z,v); } T pix4d(const int x, const int y, const int z, const int v) const { return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y), z<0?0:(z>=dimz()?dimz()-1:z), v<0?0:(v>=dimv()?dimv()-1:v)); } //! Read a pixel value with Dirichlet or Neumann boundary conditions for the three first coordinates (\c x,\c y,\c z). T pix3d(const int x, const int y, const int z, const int v, const T& out_val) const { return (x<0 || y<0 || z<0 || x>=dimx() || y>=dimy() || z>=dimz())?out_val:(*this)(x,y,z,v); } const T& pix3d(const int x, const int y, const int z, const int v=0) const { return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y), z<0?0:(z>=dimz()?dimz()-1:z),v); } //! Read a pixel value with Dirichlet or Neumann boundary conditions for the two first coordinates (\c x,\c y). T pix2d(const int x, const int y, const int z, const int v, const T& out_val) const { return (x<0 || y<0 || x>=dimx() || y>=dimy())?out_val:(*this)(x,y,z,v); } const T& pix2d(const int x,const int y,const int z=0,const int v=0) const { return (*this)(x<0?0:(x>=dimx()?dimx()-1:x), y<0?0:(y>=dimy()?dimy()-1:y),z,v); } //! Read a pixel value with Dirichlet or Neumann boundary conditions for the first coordinate \c x. T pix1d(const int x, const int y, const int z, const int v, const T& out_val) const { return (x<0 || x>=dimx())?out_val:(*this)(x,y,z,v); } const T& pix1d(const int x, const int y=0, const int z=0, const int v=0) const { return (*this)(x<0?0:(x>=dimx()?dimx()-1:x),y,z,v); } //! Read a pixel value using linear interpolation. /** \param ffx X-coordinate of the pixel (float-valued). \param ffy Y-coordinate of the pixel (float-valued). \param ffz Z-coordinate of the pixel (float-valued). \param ffv V-coordinate of the pixel (float-valued). \param out_val Out-of-border pixel value - This function allows to read pixel values with boundary checking on all coordinates. - If given coordinates are outside the image range, the value of the nearest pixel inside the image is returned (Neumann boundary conditions). - If given coordinates are float-valued, a linear interpolation is performed in order to compute the returned value. \par example: \code CImg img(2,2); // Define a greyscale 2x2 image. img(0,0) = 0; // Fill image with specified pixel values. img(1,0) = 1; img(0,1) = 2; img(1,1) = 3; const double val = img.linear_pix4d(0.5,0.5); // Return val=1.5, which is the average intensity of the four pixels values. \endcode \sa operator()(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix2d(). **/ typename cimg::largest::type linear_pix4d(const float fx,const float fy,const float fz,const float fv, const T& out_val) const { const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), v = (int)fv-(fv>=0?0:1), nx = x+1, ny = y+1, nz = z+1, nv = v+1; const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v; const T Icccc = pix4d(x,y,z,v,out_val), Inccc = pix4d(nx,y,z,v,out_val), Icncc = pix4d(x,ny,z,v,out_val), Inncc = pix4d(nx,ny,z,v,out_val), Iccnc = pix4d(x,y,nz,v,out_val), Incnc = pix4d(nx,y,nz,v,out_val), Icnnc = pix4d(x,ny,nz,v,out_val), Innnc = pix4d(nx,ny,nz,v,out_val), Icccn = pix4d(x,y,z,nv,out_val), Inccn = pix4d(nx,y,z,nv,out_val), Icncn = pix4d(x,ny,z,nv,out_val), Inncn = pix4d(nx,ny,z,nv,out_val), Iccnn = pix4d(x,y,nz,nv,out_val), Incnn = pix4d(nx,y,nz,nv,out_val), Icnnn = pix4d(x,ny,nz,nv,out_val), Innnn = pix4d(nx,ny,nz,nv,out_val); return Icccc + dx*(Inccc-Icccc + dy*(Icccc+Inncc-Icncc-Inccc + dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + dz*(Icccc+Incnc-Iccnc-Inccc + dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + dv*(Icccc+Inccn-Inccc-Icccn)) + dy*(Icncc-Icccc + dz*(Icccc+Icnnc-Iccnc-Icncc + dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + dv*(Icccc+Icncn-Icncc-Icccn)) + dz*(Iccnc-Icccc + dv*(Icccc+Iccnn-Iccnc-Icccn)) + dv*(Icccn-Icccc); } typename cimg::largest::type linear_pix4d(const float ffx,const float ffy=0,const float ffz=0,const float ffv=0) const { const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), fz = ffz<0?0:(ffz>depth-1?depth-1:ffz), fv = ffv<0?0:(ffv>dim-1?dim-1:ffv); const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz, v = (unsigned int)fv; const float dx = fx-x, dy = fy-y, dz = fz-z, dv = fv-v; const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z, nv = dv>0?v+1:v; const T &Icccc = (*this)(x,y,z,v), &Inccc = (*this)(nx,y,z,v), &Icncc = (*this)(x,ny,z,v), &Inncc = (*this)(nx,ny,z,v), &Iccnc = (*this)(x,y,nz,v), &Incnc = (*this)(nx,y,nz,v), &Icnnc = (*this)(x,ny,nz,v), &Innnc = (*this)(nx,ny,nz,v), &Icccn = (*this)(x,y,z,nv), &Inccn = (*this)(nx,y,z,nv), &Icncn = (*this)(x,ny,z,nv), &Inncn = (*this)(nx,ny,z,nv), &Iccnn = (*this)(x,y,nz,nv), &Incnn = (*this)(nx,y,nz,nv), &Icnnn = (*this)(x,ny,nz,nv), &Innnn = (*this)(nx,ny,nz,nv); return Icccc + dx*(Inccc-Icccc + dy*(Icccc+Inncc-Icncc-Inccc + dz*(Iccnc+Innnc+Icncc+Inccc-Icnnc-Incnc-Icccc-Inncc + dv*(Iccnn+Innnn+Icncn+Inccn+Icnnc+Incnc+Icccc+Inncc-Icnnn-Incnn-Icccn-Inncn-Iccnc-Innnc-Icncc-Inccc)) + dv*(Icccn+Inncn+Icncc+Inccc-Icncn-Inccn-Icccc-Inncc)) + dz*(Icccc+Incnc-Iccnc-Inccc + dv*(Icccn+Incnn+Iccnc+Inccc-Iccnn-Inccn-Icccc-Incnc)) + dv*(Icccc+Inccn-Inccc-Icccn)) + dy*(Icncc-Icccc + dz*(Icccc+Icnnc-Iccnc-Icncc + dv*(Icccn+Icnnn+Iccnc+Icncc-Iccnn-Icncn-Icccc-Icnnc)) + dv*(Icccc+Icncn-Icncc-Icccn)) + dz*(Iccnc-Icccc + dv*(Icccc+Iccnn-Iccnc-Icccn)) + dv*(Icccn-Icccc); } //! Read a pixel value using linear interpolation for the three first coordinates (\c cx,\c cy,\c cz). /** - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the three first coordinates. \sa operator()(), linear_pix4d(), linear_pix2d(), linear_pix1d(), linear_pix3d(), cubic_pix2d(). **/ typename cimg::largest::type linear_pix3d(const float fx,const float fy,const float fz,const int v, const T& out_val) const { const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), z = (int)fz-(fz>=0?0:1), nx = x+1, ny = y+1, nz = z+1; const float dx = fx-x, dy = fy-y, dz = fz-z; const T Iccc = pix3d(x,y,z,v,out_val), Incc = pix3d(nx,y,z,v,out_val), Icnc = pix3d(x,ny,z,v,out_val), Innc = pix3d(nx,ny,z,v,out_val), Iccn = pix3d(x,y,nz,v,out_val), Incn = pix3d(nx,y,nz,v,out_val), Icnn = pix3d(x,ny,nz,v,out_val), Innn = pix3d(nx,ny,nz,v,out_val); return Iccc + dx*(Incc-Iccc + dy*(Iccc+Innc-Icnc-Incc + dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + dz*(Iccc+Incn-Iccn-Incc)) + dy*(Icnc-Iccc + dz*(Iccc+Icnn-Iccn-Icnc)) + dz*(Iccn-Iccc); } typename cimg::largest::type linear_pix3d(const float ffx,const float ffy=0,const float ffz=0,const int v=0) const { const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy), fz = ffz<0?0:(ffz>depth-1?depth-1:ffz); const unsigned int x = (unsigned int)fx, y = (unsigned int)fy, z = (unsigned int)fz; const float dx = fx-x, dy = fy-y, dz = fz-z; const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y, nz = dz>0?z+1:z; const T &Iccc = (*this)(x,y,z,v), &Incc = (*this)(nx,y,z,v), &Icnc = (*this)(x,ny,z,v), &Innc = (*this)(nx,ny,z,v), &Iccn = (*this)(x,y,nz,v), &Incn = (*this)(nx,y,nz,v), &Icnn = (*this)(x,ny,nz,v), &Innn = (*this)(nx,ny,nz,v); return Iccc + dx*(Incc-Iccc + dy*(Iccc+Innc-Icnc-Incc + dz*(Iccn+Innn+Icnc+Incc-Icnn-Incn-Iccc-Innc)) + dz*(Iccc+Incn-Iccn-Incc)) + dy*(Icnc-Iccc + dz*(Iccc+Icnn-Iccn-Icnc)) + dz*(Iccn-Iccc); } //! Read a pixel value using linear interpolation for the two first coordinates (\c cx,\c cy). /** - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the two first coordinates. \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix1d(), linear_pix2d(), cubic_pix2d(). **/ typename cimg::largest::type linear_pix2d(const float fx, const float fy, const int z, const int v, const T& out_val) const { const int x = (int)fx-(fx>0?0:1), y = (int)fy-(fy>0?0:1), nx = x+1, ny = y+1; const float dx = fx-x, dy = fy-y; const T Icc = pix2d(x,y,z,v,out_val), Inc = pix2d(nx,y,z,v,out_val), Icn = pix2d(x,ny,z,v,out_val), Inn = pix2d(nx,ny,z,v,out_val); return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); } typename cimg::largest::type linear_pix2d(const float ffx, const float ffy=0, const int z=0, const int v=0) const { const float fx = ffx<0?0:(ffx>width-1?width-1:ffx), fy = ffy<0?0:(ffy>height-1?height-1:ffy); const unsigned int x = (unsigned int)fx, y = (unsigned int)fy; const float dx = fx-x, dy = fy-y; const unsigned int nx = dx>0?x+1:x, ny = dy>0?y+1:y; const T &Icc = (*this)(x,y,z,v), &Inc = (*this)(nx,y,z,v), &Icn = (*this)(x,ny,z,v), &Inn = (*this)(nx,ny,z,v); return Icc + dx*(Inc-Icc + dy*(Icc+Inn-Icn-Inc)) + dy*(Icn-Icc); } //! Read a pixel value using linear interpolation for the first coordinate \c cx. /** - Same as linear_pix4d(), except that linear interpolation and boundary checking is performed only on the first coordinate. \sa operator()(), linear_pix4d(), linear_pix3d(), linear_pix2d(), linear_pix1d(), cubic_pix1d(). **/ typename cimg::largest::type linear_pix1d(const float fx,const int y,const int z,const int v, const T& out_val) const { const int x = (int)fx-(fx>0?0:1), nx = x+1; const float dx = fx-x; const T Ic = pix1d(x,y,z,v,out_val), In = pix2d(nx,y,z,v,out_val); return Ic + dx*(In-Ic); } typename cimg::largest::type linear_pix1d(const float ffx,const int y=0,const int z=0,const int v=0) const { const float fx = ffx<0?0:(ffx>width-1?width-1:ffx); const unsigned int x = (unsigned int)fx; const float dx = fx-x; const unsigned int nx = dx>0?x+1:x; const T &Ic = (*this)(x,y,z,v), &In = (*this)(nx,y,z,v); return Ic + dx*(In-Ic); } // This function is used as a subroutine for cubic interpolation static float _cubic_R(const float x) { const float xp2 = x+2, xp1 = x+1, xm1 = x-1, nxp2 = xp2>0?xp2:0, nxp1 = xp1>0?xp1:0, nx = x>0?x:0, nxm1 = xm1>0?xm1:0; return (nxp2*nxp2*nxp2 - 4*nxp1*nxp1*nxp1 + 6*nx*nx*nx - 4*nxm1*nxm1*nxm1)/6.0f; } //! Read a pixel value using cubic interpolation for the first coordinate \c cx. /** - Same as cubic_pix2d(), except that cubic interpolation and boundary checking is performed only on the first coordinate. \sa operator()(), cubic_pix2d(), linear_pix1d(). **/ typename cimg::largest::type cubic_pix1d(const float fx, const int y, const int z, const int v, const T& out_val) const { const int x = (int)fx-(fx>=0?0:1), px = x-1, nx = x+1, ax = nx+1; const float dx = fx-x; const T a = pix2d(px,y,z,v,out_val), b = pix2d(x,y,z,v,out_val), c = pix2d(nx,y,z,v,out_val), d = pix2d(ax,y,z,v,out_val); const float Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx); return Rxp*a + Rxc*b + Rxn*c + Rxa*d; } typename cimg::largest::type cubic_pix1d(const float pfx, const int y=0, const int z=0, const int v=0) const { const float fx = pfx<0?0:(pfx>width-1?width-1:pfx); const unsigned int x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1::type cubic_pix2d(const float fx, const float fy, const int z, const int v, const T& out_val) const { const int x = (int)fx-(fx>=0?0:1), y = (int)fy-(fy>=0?0:1), px = x-1, nx = x+1, ax = nx+1, py = y-1, ny = y+1, ay = ny+1; const float dx = fx-x, dy = fy-y; const T a = pix2d(px,py,z,v,out_val), b = pix2d(x,py,z,v,out_val), c = pix2d(nx,py,z,v,out_val), d = pix2d(ax,py,z,v,out_val), e = pix2d(px, y,z,v,out_val), f = pix2d(x, y,z,v,out_val), g = pix2d(nx, y,z,v,out_val), h = pix2d(ax, y,z,v,out_val), i = pix2d(px,ny,z,v,out_val), j = pix2d(x,ny,z,v,out_val), k = pix2d(nx,ny,z,v,out_val), l = pix2d(ax,ny,z,v,out_val), m = pix2d(px,ay,z,v,out_val), n = pix2d(x,ay,z,v,out_val), o = pix2d(nx,ay,z,v,out_val), p = pix2d(ax,ay,z,v,out_val); const float Rxp = _cubic_R(-1-dx), Rxc = _cubic_R(dx), Rxn = _cubic_R(1-dx), Rxa = _cubic_R(2-dx), Ryp = _cubic_R(dy+1), Ryc = _cubic_R(dy), Ryn = _cubic_R(dy-1), Rya = _cubic_R(dy-2); return Rxp*Ryp*a + Rxc*Ryp*b + Rxn*Ryp*c + Rxa*Ryp*d + Rxp*Ryc*e + Rxc*Ryc*f + Rxn*Ryc*g + Rxa*Ryc*h + Rxp*Ryn*i + Rxc*Ryn*j + Rxn*Ryn*k + Rxa*Ryn*l + Rxp*Rya*m + Rxc*Rya*n + Rxn*Rya*o + Rxa*Rya*p; } typename cimg::largest::type cubic_pix2d(const float pfx, const float pfy=0, const int z=0, const int v=0) const { const float fx = pfx<0?0:(pfx>width-1?width-1:pfx), fy = pfy<0?0:(pfy>height-1?height-1:pfy); const unsigned int x = (unsigned int)fx, px = (int)x-1>=0?x-1:0, nx = x+1=0?y-1:0, ny = y+1 img("foo.jpg"); // Load image from a JPEG file. img.print("Image : foo.jpg",1); // Print image informations and statistics. \endcode \sa CImgStats **/ const CImg& print(const char *title=0, const unsigned int print_flag=1) const { std::fprintf(stderr,"%-8s(this=%p): { size=(%u,%u,%u,%u), data=(%s*)%p (%s)", title?title:"CImg",(void*)this, width,height,depth,dim,pixel_type(),(void*)data, is_shared?"shared":"not shared"); if (is_empty()) { std::fprintf(stderr,", [Undefined pixel data] }\n"); return *this; } if (print_flag>=1) { const CImgStats st(*this); std::fprintf(stderr,", min=%g, mean=%g [var=%g], max=%g, pmin=(%d,%d,%d,%d), pmax=(%d,%d,%d,%d)", st.min,st.mean,st.variance,st.max,st.xmin,st.ymin,st.zmin,st.vmin,st.xmax,st.ymax,st.zmax,st.vmax); } if (print_flag>=2 || size()<=16) { std::fprintf(stderr," }\n%s = [ ",title?title:"data"); cimg_forXYZV(*this,x,y,z,k) std::fprintf(stderr,"%g%s",(double)(*this)(x,y,z,k), ((x+1)*(y+1)*(z+1)*(k+1)==(int)size()?" ]\n":(((x+1)%width==0)?" ; ":" "))); } else std::fprintf(stderr," }\n"); return *this; } //! Display informations about the image on the standard output. const CImg& print(const unsigned int print_flag) const { return print(0,print_flag); } //@} //------------------------------------------ // //! \name Arithmetic and Boolean Operators //@{ //------------------------------------------ //! Assignment operator. /** This operator assigns a copy of the input image \p img to the current instance image. \param img The input image to copy. \remark - This operator is strictly equivalent to the function assign(const CImg< t >&) and has exactly the same properties. \see assign(const CImg< t >&). **/ template CImg& operator=(const CImg& img) { return assign(img); } CImg& operator=(const CImg& img) { return assign(img); } //! Assign values of a C-array to the instance image. /** \param buf Pointer to a C-style array having a size of (at least) this->size(). - Replace pixel values by the content of the array \c buf. - Warning : the value types in the array and in the image must be the same. \par example: \code 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. CImg matrice(4,4); // Define a 4x4 greyscale image. matrice = tab; // Fill the image by the values in tab. \endcode **/ CImg& operator=(const T *buf) { if (buf) std::memcpy(data,buf,size()*sizeof(T)); else assign(); return *this; } //! Assign a value to each image pixel of the instance image. CImg& operator=(const T& val) { return fill(val); } //! Operator+ /** \remark - This operator can be used to get a non-shared copy of an image. **/ CImg operator+() const { return CImg(*this,false); } //! Operator+=; #ifdef cimg_use_visualcpp6 CImg& operator+=(const T& val) { #else template CImg& operator+=(const t& val) { #endif cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)+val); return *this; } //! Operator+= template CImg& operator+=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); t *ptrs = img.data+smin; for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)+(*(--ptrs)))); return *this; } //! Operator++; CImg& operator++() { cimg_for(*this,ptr,T) (*ptr)++; return *this; } //! Operator-. CImg operator-() const { return CImg(width,height,depth,dim,0)-=*this; } //! Operator-=. #ifdef cimg_use_visualcpp6 CImg& operator-=(const T& val) { #else template CImg& operator-=(const t& val) { #endif cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)-val); return *this; } //! Operator-=. template CImg& operator-=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); t *ptrs = img.data+smin; for (T *ptrd = data+smin; ptrd>data; --ptrd, (*ptrd)=(T)((*ptrd)-(*(--ptrs)))); return *this; } //! Operator--. CImg& operator--() { cimg_for(*this,ptr,T) *ptr=*ptr-(T)1; return *this; } //! Operator*=. #ifdef cimg_use_visualcpp6 CImg& operator*=(const double val) { #else template CImg& operator*=(const t& val) { #endif cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)*val); return *this; } //! Operator*=. template CImg& operator*=(const CImg& img) { return ((*this)*img).swap(*this); } //! Operator/=. #ifdef cimg_use_visualcpp6 CImg& operator/=(const double val) { #else template CImg& operator/=(const t& val) { #endif cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)/val); return *this; } //! Operator/=. template CImg& operator/=(const CImg& img) { return assign(*this*img.get_inverse()); } //! Modulo. CImg operator%(const CImg& img) const { return (+*this)%=img; } //! Modulo. CImg operator%(const T& val) const { return (+*this)%=val; } //! In-place modulo. CImg& operator%=(const T& val) { cimg_for(*this,ptr,T) (*ptr)=(T)cimg::mod(*ptr,val); return *this; } //! In-place modulo. CImg& operator%=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); for (T *ptrs = img.data + smin, *ptrd = data + smin; ptrd>data; ) { T& val = *(--ptrd); val = (T)cimg::mod(val,*(--ptrs)); } return *this; } //! Bitwise AND. CImg operator&(const CImg& img) const { return (+*this)&=img; } //! Bitwise AND. CImg operator&(const T& val) const { return (+*this)&=val; } //! In-place bitwise AND. CImg& operator&=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; ) { T& val = *(--ptrd); val = (T)((long)val & (long)*(--ptrs)); } return *this; } //! In-place bitwise AND. CImg& operator&=(const T& val) { cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr & (long)val); return *this; } //! Bitwise OR. CImg operator|(const CImg& img) const { return (+*this)|=img; } //! Bitwise OR. CImg operator|(const T& val) const { return (+*this)|=val; } //! In-place bitwise OR. CImg& operator|=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; ) { T& val = *(--ptrd); val = (T)((long)val | (long)*(--ptrs)); } return *this; } //! In-place bitwise OR. CImg& operator|=(const T& val) { cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr | (long)val); return *this; } //! Bitwise XOR. CImg operator^(const CImg& img) const { return (+*this)^=img; } //! Bitwise XOR. CImg operator^(const T& val) const { return (+*this)^=val; } //! In-place bitwise XOR. CImg& operator^=(const CImg& img) { const unsigned int smin = cimg::min(size(),img.size()); for (T *ptrs=img.data+smin, *ptrd=data+smin; ptrd>data; ) { T& val = *(--ptrd); val =(T)((long)val ^ (long)*(--ptrs)); } return *this; } //! In-place bitwise XOR. CImg& operator^=(const T& val) { cimg_for(*this,ptr,T) *ptr = (T)((long)*ptr ^ (long)val); return *this; } //! Bitwise NOT. CImg operator~() const { CImg res(width,height,depth,dim); const T *ptrs = end(); cimg_for(res,ptrd,T) *ptrd=(T)~(long)*(--ptrs); return res; } //! Bitwise shift CImg& operator<<=(const int n) { cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)<>=(const int n) { cimg_for(*this,ptr,T) *ptr = (T)(((long)*ptr)>>n); return *this; } //! Bitwise shift CImg operator>>(const int n) const { return (+*this)>>=n; } //! Boolean equality. template bool operator==(const CImg& img) const { const unsigned int siz = size(); bool vequal = true; if (siz!=img.size()) return false; t *ptrs=img.data+siz; for (T *ptrd=data+siz; vequal && ptrd>data; vequal=vequal&&((*(--ptrd))==(*(--ptrs)))); return vequal; } //! Boolean difference. template bool operator!=(const CImg& img) const { return !((*this)==img); } //! Get a new list template CImgList::type> operator<<(const CImg& img) const { typedef typename cimg::largest::type restype; return CImgList(*this,img); } //@} //--------------------------------------- // //! \name Usual Mathematics //@{ //--------------------------------------- //! Apply a R->R function on all image value. template CImg& apply(t& func) { cimg_for(*this,ptr,T) *ptr = func(*ptr); return *this; } //! Return an image where each pixel value is equal to func(x). template CImg get_apply(t& func) const { return (+*this).apply(func); } //! In-place pointwise multiplication between \c *this and \c img. /** This is the in-place version of get_mul(). \sa get_mul(). **/ template CImg& mul(const CImg& img) { t *ptrs = img.data; T *ptrf = data + cimg::min(size(),img.size()); for (T* ptrd = data; ptrd CImg::type> get_mul(const CImg& img) const { typedef typename cimg::largest::type restype; return CImg(*this,false).mul(img); } //! Replace the image by the pointwise division between \p *this and \p img. /** This is the in-place version of get_div(). \see get_div(). **/ template CImg& div(const CImg& img) { t *ptrs = img.data; T *ptrf = data + cimg::min(size(),img.size()); for (T* ptrd = data; ptrd CImg::type> get_div(const CImg& img) const { typedef typename cimg::largest::type restype; return CImg(*this,false).div(img); } //! Replace the image by the pointwise max operator between \p *this and \p img /** This is the in-place version of get_max(). \see get_max(). **/ template CImg& max(const CImg& img) { t *ptrs = img.data; T *ptrf = data + cimg::min(size(),img.size()); for (T* ptrd = data; ptrd CImg::type> get_max(const CImg& img) const { typedef typename cimg::largest::type restype; return CImg(*this,false).max(img); } //! Replace the image by the pointwise max operator between \p *this and \p val /** This is the in-place version of get_max(). \see get_max(). **/ CImg& max(const T& val) { cimg_for(*this,ptr,T) (*ptr)=cimg::max(*ptr,val); return *this; } //! Return the image corresponding to the max value for each pixel. /** \param val = second argument of the max operator (the first one is *this). \see max(), min(), get_min() **/ CImg get_max(const T& val) const { return (+*this).max(val); } //! Replace the image by the pointwise min operator between \p *this and \p img /** This is the in-place version of get_min(). \see get_min(). **/ template CImg& min(const CImg& img) { t *ptrs = img.data; T *ptrf = data + cimg::min(size(),img.size()); for (T* ptrd = data; ptrd CImg::type> get_min(const CImg& img) const { typedef typename cimg::largest::type restype; return CImg(*this,false).min(img); } //! Replace the image by the pointwise min operator between \p *this and \p val /** This is the in-place version of get_min(). \see get_min(). **/ CImg& min(const T& val) { cimg_for(*this,ptr,T) (*ptr)=cimg::min(*ptr,val); return *this; } //! Return the image corresponding to the min value for each pixel. /** \param val = second argument of the min operator (the first one is *this). \see min(), max(), get_max() **/ CImg get_min(const T& val) const { return (+*this).min(val); } //! Replace each image pixel by its square root. /** \see get_sqrt() **/ CImg& sqrt() { cimg_for(*this,ptr,T) (*ptr)=(T)std::sqrt((double)(*ptr)); return *this; } //! Return the image of the square root of the pixel values. /** \see sqrt() **/ CImg::type> get_sqrt() const { typedef typename cimg::largest::type restype; return CImg(*this,false).sqrt(); } //! Replace each image pixel by its exponential. CImg& exp() { cimg_for(*this,ptr,T) (*ptr)=(T)std::exp((double)(*ptr)); return *this; } //! Return the image of the exponential of the pixel values. CImg::type> get_exp() const { typedef typename cimg::largest::type restype; return CImg(*this,false).exp(); } //! Replace each image pixel by its log. /** \see get_log(), log10(), get_log10() **/ CImg& log() { cimg_for(*this,ptr,T) (*ptr)=(T)std::log((double)(*ptr)); return *this; } //! Return the image of the log of the pixel values. /** \see log(), log10(), get_log10() **/ CImg::type> get_log() const { typedef typename cimg::largest::type restype; return CImg(*this,false).log(); } //! Replace each image pixel by its log10. /** \see get_log10(), log(), get_log() **/ CImg& log10() { cimg_for(*this,ptr,T) (*ptr)=(T)std::log10((double)(*ptr)); return *this; } //! Return the image of the log10 of the pixel values. /** \see log10(), log(), get_log() **/ CImg::type> get_log10() const { typedef typename cimg::largest::type restype; return CImg(*this,false).log10(); } //! Replace each image pixel by its power by \p p. /** \param p = power \see get_pow(), sqrt(), get_sqrt() **/ CImg& pow(const double p) { if (p==0) return fill(1); if (p==0.5) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr=(T)std::sqrt((double)val); } return *this; } if (p==1) return *this; if (p==2) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr=val*val; } return *this; } if (p==3) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val; } return *this; } if (p==4) { cimg_for(*this,ptr,T) { const T& val = *ptr; *ptr=val*val*val*val; } return *this; } cimg_for(*this,ptr,T) (*ptr)=(T)std::pow((double)(*ptr),p); return *this; } //! Return the image of the square root of the pixel values. /** \param p = power \see pow(), sqrt(), get_sqrt() **/ CImg::type> get_pow(const double p) const { typedef typename cimg::largest::type restype; return CImg(*this,false).pow(p); } //! Return each image pixel (*this)(x,y,z,k) by its power by \p img(x,y,z,k) /** In-place version **/ template CImg& pow(const CImg& img) { t *ptrs = img.data; T *ptrf = data + cimg::min(size(),img.size()); for (T* ptrd = data; ptrd CImg::type> get_pow(const CImg& img) const { typedef typename cimg::largest::type restype; return CImg(*this,false).pow(img); } //! Replace each pixel value by its absolute value. /** \see get_abs() **/ CImg& abs() { cimg_for(*this,ptr,T) (*ptr)=cimg::abs(*ptr); return *this; } //! Return the image of the absolute value of the pixel values. /** \see abs() **/ CImg::type> get_abs() const { typedef typename cimg::largest::type restype; return CImg(*this,false).abs(); } //! Replace each image pixel by its cosinus. /** \see get_cos(), sin(), get_sin(), tan(), get_tan() **/ CImg& cos() { cimg_for(*this,ptr,T) (*ptr)=(T)std::cos((double)(*ptr)); return *this; } //! Return the image of the cosinus of the pixel values. /** \see cos(), sin(), get_sin(), tan(), get_tan() **/ CImg::type> get_cos() const { typedef typename cimg::largest::type restype; return CImg(*this,false).cos(); } //! Replace each image pixel by its sinus. /** \see get_sin(), cos(), get_cos(), tan(), get_tan() **/ CImg& sin() { cimg_for(*this,ptr,T) (*ptr)=(T)std::sin((double)(*ptr)); return *this; } //! Return the image of the sinus of the pixel values. /** \see sin(), cos(), get_cos(), tan(), get_tan() **/ CImg::type> get_sin() const { typedef typename cimg::largest::type restype; return CImg(*this,false).sin(); } //! Replace each image pixel by its tangent. /** \see get_tan(), cos(), get_cos(), sin(), get_sin() **/ CImg& tan() { cimg_for(*this,ptr,T) (*ptr)=(T)std::tan((double)(*ptr)); return *this; } //! Return the image of the tangent of the pixel values. /** \see tan(), cos(), get_cos(), sin(), get_sin() **/ CImg::type> get_tan() const { typedef typename cimg::largest::type restype; return CImg(*this,false).tan(); } //! Replace each image pixel by its arc-cosinus. CImg& acos() { cimg_for(*this,ptr,T) (*ptr)=(T)std::acos((double)(*ptr)); return *this; } //! Return the image of the arc-cosinus of the pixel values. CImg::type> get_acos() const { typedef typename cimg::largest::type restype; return CImg(*this,false).acos(); } //! Replace each image pixel by its arc-sinus. CImg& asin() { cimg_for(*this,ptr,T) (*ptr)=(T)std::asin((double)(*ptr)); return *this; } //! Return the image of the arc-sinus of the pixel values. CImg::type> get_asin() const { typedef typename cimg::largest::type restype; return CImg(*this,false).asin(); } //! Replace each image pixel by its arc-tangent. CImg& atan() { cimg_for(*this,ptr,T) (*ptr)=(T)std::atan((double)(*ptr)); return *this; } //! Return the image of the arc-tangent of the pixel values. CImg::type> get_atan() const { typedef typename cimg::largest::type restype; return CImg(*this,false).atan(); } //! Round image values /** \param round_type : 0 (nearest), 1 (forward), 2 (backward). **/ CImg& round(const float x, const unsigned int round_type=0) { cimg_for(*this,ptr,T) (*ptr)=(T)cimg::round(*ptr,x,round_type); return *this; } //! Return the image of rounded values CImg get_round(const float x, const unsigned int round_type=0) const { return (+*this).round(x,round_type); } //! Return the MSE (Mean-Squared Error) between two images. template double MSE(const CImg& img) const { if (img.size()!=size()) throw CImgArgumentException("CImg<%s>::MSE() : Instance image (%u,%u,%u,%u) and given image (%u,%u,%u,%u) have different dimensions.", pixel_type(),width,height,depth,dim,img.width,img.height,img.depth,img.dim); double vMSE = 0; const t* ptr2 = img.end(); cimg_for(*this,ptr1,T) { const double diff = (double)*ptr1 - (double)*(--ptr2); vMSE += diff*diff; } vMSE/=img.size(); return vMSE; } //! Return the PSNR between two images. template double PSNR(const CImg& img, const double valmax=255.0) const { const double vMSE = std::sqrt(MSE(img)); return (vMSE!=0)?(20*std::log10(valmax/vMSE)):(cimg::type::max()); } //@} //----------------------------------- // //! \name Usual Image Transformations //@{ //----------------------------------- //! Fill an image by a value \p val. /** \param val = fill value \note All pixel values of the instance image will be initialized by \p val. \see operator=(). **/ CImg& fill(const T& val) { if (!is_empty()) { if (val!=0 && sizeof(T)!=1) cimg_for(*this,ptr,T) *ptr=val; else std::memset(data,(int)val,size()*sizeof(T)); } return *this; } CImg get_fill(const T& val) const { return (+*this).fill(val); } //! Fill sequentially all pixel values with values \a val0 and \a val1 respectively. /** \param val0 = fill value 1 \param val1 = fill value 2 **/ CImg& fill(const T& val0, const T& val1) { if (!is_empty()) { T *ptr, *ptr_end = end()-1; for (ptr=data; ptrb)?b:*ptr); return *this; } //! Return the image of cutted values. /** \param a = minimum pixel value after cut. \param b = maximum pixel value after cut. \see cut(), normalize(), get_normalize(). **/ CImg get_cut(const T& a, const T& b) const { return (+*this).cut(a,b); } //! Quantize pixel values into \n levels. /** \param n = number of quantification levels \see get_quantize(). **/ CImg& quantize(const unsigned int n=256) { if (!is_empty()) { if (!n) throw CImgArgumentException("CImg<%s>::quantize() : Cannot quantize image to 0 values.", pixel_type()); const CImgStats st(*this,false); const double range = st.max-st.min; if (range>0) cimg_for(*this,ptr,T) { const unsigned int val = (unsigned int)((*ptr-st.min)*n/range); *ptr = (T)(st.min + cimg::min(val,n-1)*range); } } return *this; } //! Return a quantified image, with \n levels. /** \param n = number of quantification levels \see quantize(). **/ CImg get_quantize(const unsigned int n=256) const { return (+*this).quantize(n); } //! Threshold the image. /** \param thres = threshold \see get_threshold(). **/ CImg& threshold(const T& thres) { if (!is_empty()) cimg_for(*this,ptr,T) *ptr = *ptr<=thres?(T)0:(T)1; return *this; } //! Return a thresholded image. /** \param thres = threshold. \see threshold(). **/ CImg get_threshold(const T& thres) const { return (+*this).threshold(thres); } //! Return a rotated image. /** \param angle = rotation angle (in degrees). \param cond = rotation type. can be : - 0 = zero-value at borders - 1 = repeat image at borders - 2 = zero-value at borders and linear interpolation \note Returned image will probably have a different size than the instance image *this. \see rotate() **/ CImg get_rotate(const float angle, const unsigned int cond=3) const { if (is_empty()) return CImg(); CImg dest; const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0), ca=(float)std::cos(rad), sa=(float)std::sin(rad); if (cond!=1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles const int wm1 = dimx()-1, hm1 = dimy()-1; const int iangle = (int)nangle/90; switch (iangle) { case 1: { dest.assign(height,width,depth,dim); cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(y,hm1-x,z,v); } break; case 2: { dest.assign(width,height,depth,dim); cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-x,hm1-y,z,v); } break; case 3: { dest.assign(height,width,depth,dim); cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(wm1-y,x,z,v); } break; default: return *this; } } else { // generic version const float ux = (float)(cimg::abs(width*ca)), uy = (float)(cimg::abs(width*sa)), vx = (float)(cimg::abs(height*sa)), vy = (float)(cimg::abs(height*ca)), w2 = 0.5f*width, h2 = 0.5f*height, dw2 = 0.5f*(ux+vx), dh2 = 0.5f*(uy+vy); dest.assign((int)(ux+vx), (int)(uy+vy),depth,dim); switch (cond) { case 0: { cimg_forXY(dest,x,y) cimg_forZV(*this,z,v) dest(x,y,z,v) = pix2d((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)(h2 - (x-dw2)*sa + (y-dh2)*ca),z,v,0); } break; case 1: { cimg_forXY(dest,x,y) cimg_forZV(*this,z,v) dest(x,y,z,v) = (*this)(cimg::mod((int)(w2 + (x-dw2)*ca + (y-dh2)*sa),(int)width), cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),(int)height),z,v); } break; case 2: { cimg_forXY(dest,x,y) { const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca; cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)linear_pix2d(X,Y,z,v,0); } } break; default: { cimg_forXY(dest,x,y) { const float X = w2 + (x-dw2)*ca + (y-dh2)*sa, Y = h2 - (x-dw2)*sa + (y-dh2)*ca; cimg_forZV(*this,z,v) dest(x,y,z,v) = (T)cubic_pix2d(X,Y,z,v,0); } } break; } } return dest; } //! Rotate the image /** \param angle = rotation angle (in degrees). \param cond = rotation type. can be : - 0 = zero-value at borders - 1 = repeat image at borders - 2 = zero-value at borders and linear interpolation \see get_rotate() **/ CImg& rotate(const float angle,const unsigned int cond=3) { return get_rotate(angle,cond).swap(*this); } //! Return a rotated image around the point (\c cx,\c cy). /** \param angle = rotation angle (in degrees). \param cx = X-coordinate of the rotation center. \param cy = Y-coordinate of the rotation center. \param zoom = zoom. \param cond = rotation type. can be : - 0 = zero-value at borders - 1 = repeat image at borders - 2 = zero-value at borders and linear interpolation \see rotate() **/ CImg get_rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=3) const { if (is_empty()) return CImg(); CImg dest(width,height,depth,dim); const float nangle = cimg::mod(angle,360.0f), rad = (float)((nangle*cimg::PI)/180.0), ca=(float)std::cos(rad)/zoom, sa=(float)std::sin(rad)/zoom; if (cond!=1 && zoom==1 && cimg::mod(nangle,90.0f)==0) { // optimized version for orthogonal angles const int iangle = (int)nangle/90; switch (iangle) { case 1: { dest.fill(0); const unsigned int xmin = cimg::max(0,(dimx()-dimy())/2), xmax = cimg::min(width,xmin+height), ymin = cimg::max(0,(dimy()-dimx())/2), ymax = cimg::min(height,ymin+width), xoff = xmin + cimg::min(0,(dimx()-dimy())/2), yoff = ymin + cimg::min(0,(dimy()-dimx())/2); cimg_forZV(dest,z,v) for (unsigned int y=ymin; y(); const unsigned int tdx = pdx<0?-pdx*width/100:pdx, tdy = pdy<0?-pdy*height/100:pdy, tdz = pdz<0?-pdz*depth/100:pdz, tdv = pdv<0?-pdv*dim/100:pdv, dx = tdx?tdx:1, dy = tdy?tdy:1, dz = tdz?tdz:1, dv = tdv?tdv:1; if (width==dx && height==dy && depth==dz && dim==dv) return *this; if (is_empty()) return CImg(dx,dy,dz,dv,0); CImg res; switch (interp) { case -1: // Raw resizing std::memcpy(res.assign(dx,dy,dz,dv,0).data,data,sizeof(T)*cimg::min(size(),(long unsigned int)dx*dy*dz*dv)); break; case 0: // Zero filling res.assign(dx,dy,dz,dv,0).draw_image(*this,0,0,0,0); break; case 1: { // Nearest-neighbor interpolation res.assign(dx,dy,dz,dv); unsigned int *const offx = new unsigned int[dx], *const offy = new unsigned int[dy+1], *const offz = new unsigned int[dz+1], *const offv = new unsigned int[dv+1], *poffx, *poffy, *poffz, *poffv, curr, old; const unsigned int wh = width*height, whd = width*height*depth, rwh = dx*dy, rwhd = dx*dy*dz; poffx = offx; curr=0; { cimg_forX(res,x) { old=curr; curr=(x+1)*width/dx; *(poffx++) = (unsigned int)curr-(unsigned int)old; }} 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; 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; 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; T *ptrd = res.ptr(); const T* ptrv = ptr(); poffv = offv; for (unsigned int k=0; kwidth )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx, sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy, sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz, sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv; unsigned int *const off = new unsigned int[dimmax], *poff; float *const foff = new float[dimmax], *pfoff, old, curr; CImg resx, resy, resz, resv; T *ptrd; if (dx!=width) { if (width==1) resx = get_resize(dx,height,depth,dim,1,0); else { resx.assign(dx,height,depth,dim); curr = old = 0; poff = off; pfoff = foff; cimg_forX(resx,x) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sx; *(poff++) = (unsigned int)curr-(unsigned int)old; } ptrd = resx.ptr(); const T *ptrs0 = ptr(); cimg_forYZV(resx,y,z,k) { poff = off; pfoff = foff; const T *ptrs = ptrs0, *const ptrsmax = ptrs0 + (width-1); cimg_forX(resx,x) { const float alpha = *(pfoff++); const T val1 = *ptrs, val2 = ptrswidth )?(dx>1?(width-1.0f)/(dx-1) :0):(float)width/dx, sy = (border_condition<0 && dy>height)?(dy>1?(height-1.0f)/(dy-1):0):(float)height/dy, sz = (border_condition<0 && dz>depth )?(dz>1?(depth-1.0f)/(dz-1) :0):(float)depth/dz, sv = (border_condition<0 && dv>dim )?(dv>1?(dim-1.0f)/(dv-1) :0):(float)dim/dv; res.assign(dx,dy,dz,dv); float cx, cy, cz, ck = 0; cimg_forV(res,k) { cz = 0; cimg_forZ(res,z) { cy = 0; cimg_forY(res,y) { cx = 0; cimg_forX(res,x) { res(x,y,z,k) = (T)(border_condition?cubic_pix2d(cx,cy,(int)cz,(int)ck):cubic_pix2d(cx,cy,(int)cz,(int)ck,0)); cx+=sx; } cy+=sy; } cz+=sz; } ck+=sv; } } break; default: // Invalid interpolation method throw CImgArgumentException("CImg<%s>::resize() : Invalid interpolation method (%d) specified.", pixel_type(),interp); } return res; } //! Return a resized image. /** \param src = Image giving the geometry of the resize. \param interp = Resizing type : - 1 = raw memory - 0 = no interpolation : additional space is filled with 0. - 1 = bloc interpolation (nearest point). - 2 = mosaic : image is repeated if necessary. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = bi-cubic interpolation. \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ template CImg get_resize(const CImg& src, const int interp=1, const int border_condition=-1) const { return get_resize(src.width,src.height,src.depth,src.dim,interp,border_condition); } //! Return a resized image. /** \param disp = Display giving the geometry of the resize. \param interp = Resizing type : - 0 = no interpolation : additional space is filled with 0. - 1 = bloc interpolation (nearest point). - 2 = mosaic : image is repeated if necessary. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = bi-cubic interpolation. \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ CImg get_resize(const CImgDisplay& disp,const int interp=1, const int border_condition=-1) const { return get_resize(disp.width,disp.height,depth,dim,interp,border_condition); } //! Resize the image. /** \param pdx = Number of columns (new size along the X-axis). \param pdy = Number of rows (new size along the Y-axis). \param pdz = Number of slices (new size along the Z-axis). \param pdv = Number of vector-channels (new size along the V-axis). \param interp = Resizing type : - 0 = no interpolation : additional space is filled with 0. - 1 = bloc interpolation (nearest point). - 2 = mosaic : image is repeated if necessary. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = bi-cubic interpolation. \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ CImg& resize(const int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100, const int interp=1, const int border_condition=-1) { if (!pdx || !pdy || !pdz || !pdv) return assign(); const unsigned int dx = pdx<0?-pdx*width/100:pdx, dy = pdy<0?-pdy*height/100:pdy, dz = pdz<0?-pdz*depth/100:pdz, dv = pdv<0?-pdv*dim/100:pdv; if (width==dx && height==dy && depth==dz && dim==dv) return *this; if (interp==-1 && dx*dy*dz*dv==size()) { width=dx; height=dy; depth=dz; dim=dv; return *this; } return get_resize(dx,dy,dz,dv,interp,border_condition).swap(*this); } //! Resize the image. /** \param src = Image giving the geometry of the resize. \param interp = Resizing type : - 0 = no interpolation : additional space is filled with 0. - 1 = bloc interpolation (nearest point). - 2 = mosaic : image is repeated if necessary. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = bi-cubic interpolation. \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ template CImg& resize(const CImg& src, const int interp=1, const int border_condition=-1) { return resize(src.width,src.height,src.depth,src.dim,interp,border_condition); } //! Resize the image /** \param disp = Display giving the geometry of the resize. \param interp = Resizing type : - 0 = no interpolation : additional space is filled with 0. - 1 = bloc interpolation (nearest point). - 2 = mosaic : image is repeated if necessary. - 3 = linear interpolation. - 4 = grid interpolation. - 5 = bi-cubic interpolation. \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). **/ CImg& resize(const CImgDisplay& disp, const int interp=1, const int border_condition=-1) { return resize(disp.width,disp.height,depth,dim,interp,border_condition); } //! Permute axes order. /** This function permutes image axes. \param permut = String describing the permutation (4 characters). **/ CImg get_permute_axes(const char *permut="vxyz") const { if (is_empty() || !permut) return (+*this); CImg res; const T* ptr = data; if (!cimg::strncasecmp(permut,"xyzv",4)) return (+*this); if (!cimg::strncasecmp(permut,"xyvz",4)) { res.assign(width,height,dim,depth); cimg_forXYZV(*this,x,y,z,v) res(x,y,v,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"xzyv",4)) { res.assign(width,depth,height,dim); cimg_forXYZV(*this,x,y,z,v) res(x,z,y,v) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"xzvy",4)) { res.assign(width,depth,dim,height); cimg_forXYZV(*this,x,y,z,v) res(x,z,v,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"xvyz",4)) { res.assign(width,dim,height,depth); cimg_forXYZV(*this,x,y,z,v) res(x,v,y,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"xvzy",4)) { res.assign(width,dim,depth,height); cimg_forXYZV(*this,x,y,z,v) res(x,v,z,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yxzv",4)) { res.assign(height,width,depth,dim); cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yxvz",4)) { res.assign(height,width,dim,depth); cimg_forXYZV(*this,x,y,z,v) res(y,x,v,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yzxv",4)) { res.assign(height,depth,width,dim); cimg_forXYZV(*this,x,y,z,v) res(y,z,x,v) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yzvx",4)) { res.assign(height,depth,dim,width); cimg_forXYZV(*this,x,y,z,v) res(y,z,v,x) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yvxz",4)) { res.assign(height,dim,width,depth); cimg_forXYZV(*this,x,y,z,v) res(y,v,x,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"yvzx",4)) { res.assign(height,dim,depth,width); cimg_forXYZV(*this,x,y,z,v) res(y,v,z,x) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zxyv",4)) { res.assign(depth,width,height,dim); cimg_forXYZV(*this,x,y,z,v) res(z,x,y,v) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zxvy",4)) { res.assign(depth,width,dim,height); cimg_forXYZV(*this,x,y,z,v) res(z,x,v,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zyxv",4)) { res.assign(depth,height,width,dim); cimg_forXYZV(*this,x,y,z,v) res(z,y,x,v) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zyvx",4)) { res.assign(depth,height,dim,width); cimg_forXYZV(*this,x,y,z,v) res(z,y,v,x) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zvxy",4)) { res.assign(depth,dim,width,height); cimg_forXYZV(*this,x,y,z,v) res(z,v,x,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"zvyx",4)) { res.assign(depth,dim,height,width); cimg_forXYZV(*this,x,y,z,v) res(z,v,y,x) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vxyz",4)) { res.assign(dim,width,height,depth); cimg_forXYZV(*this,x,y,z,v) res(v,x,y,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vxzy",4)) { res.assign(dim,width,depth,height); cimg_forXYZV(*this,x,y,z,v) res(v,x,z,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vyxz",4)) { res.assign(dim,height,width,depth); cimg_forXYZV(*this,x,y,z,v) res(v,y,x,z) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vyzx",4)) { res.assign(dim,height,depth,width); cimg_forXYZV(*this,x,y,z,v) res(v,y,z,x) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vzxy",4)) { res.assign(dim,depth,width,height); cimg_forXYZV(*this,x,y,z,v) res(v,z,x,y) = *(ptr++); return res; } if (!cimg::strncasecmp(permut,"vzyx",4)) { res.assign(dim,depth,height,width); cimg_forXYZV(*this,x,y,z,v) res(v,z,y,x) = *(ptr++); return res; } throw CImgArgumentException("CImg<%s>::permute_axes() : Invalid input permutation '%s'.",pixel_type(),permut); return res; } //! Permute axes order (in-place version). CImg& permute_axes(const char *order="vxyz") { return get_permute_axes(order).swap(*this); } //! Return an half-resized image, using a special filter. /** \see resize_halfXY(), resize(), get_resize(). **/ CImg get_resize_halfXY() const { typedef typename cimg::largest::type ftype; if (is_empty()) return CImg(); CImg mask = CImg::matrix(0.07842776544f, 0.1231940459f, 0.07842776544f, 0.1231940459f, 0.1935127547f, 0.1231940459f, 0.07842776544f, 0.1231940459f, 0.07842776544f); CImg_3x3(I,ftype); CImg dest(width/2,height/2,depth,dim); cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) if (x%2 && y%2) dest(x/2,y/2,z,k) = (T)cimg_conv3x3(I,mask); return dest; } //! Half-resize the image, using a special filter /** \see get_resize_halfXY(), resize(), get_resize(). **/ CImg& resize_halfXY() { return get_resize_halfXY().swap(*this); } //! Return a square region of the image, as a new image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param z0 = Z-coordinate of the upper-left crop rectangle corner. \param v0 = V-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param z1 = Z-coordinate of the lower-right crop rectangle corner. \param v1 = V-coordinate of the lower-right crop rectangle corner. \param border_condition = Dirichlet (false) or Neumann border conditions. \see crop() **/ CImg get_crop(const int x0, const int y0 ,const int z0, const int v0, const int x1, const int y1, const int z1, const int v1, const bool border_condition=false) const { if (is_empty()) return *this; const int nx0 = x0=dimx() || ny0<0 || ny1>=dimy() || nz0<0 || nz1>=dimz() || nv0<0 || nv1>=dimv()) { if (border_condition) cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = pix4d(nx0+x,ny0+y,nz0+z,nv0+v); else dest.fill(0).draw_image(*this,-nx0,-ny0,-nz0,-nv0); } else dest.draw_image(*this,-nx0,-ny0,-nz0,-nv0); return dest; } //! Return a square region of the image, as a new image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param z0 = Z-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param z1 = Z-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see crop() **/ CImg get_crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool border_condition=false) const { return get_crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition); } //! Return a square region of the image, as a new image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see crop() **/ CImg get_crop(const int x0, const int y0, const int x1, const int y1, const bool border_condition=false) const { return get_crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition); } //! Return a square region of the image, as a new image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see crop() **/ CImg get_crop(const int x0, const int x1, const bool border_condition=false) const { return get_crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition); } //! Replace the image by a square region of the image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param z0 = Z-coordinate of the upper-left crop rectangle corner. \param v0 = V-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param z1 = Z-coordinate of the lower-right crop rectangle corner. \param v1 = V-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see get_crop() **/ CImg& crop(const int x0, const int y0, const int z0, const int v0, const int x1, const int y1, const int z1, const int v1, const bool border_condition=false) { return get_crop(x0,y0,z0,v0,x1,y1,z1,v1,border_condition).swap(*this); } //! Replace the image by a square region of the image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param z0 = Z-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param z1 = Z-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see get_crop() **/ CImg& crop(const int x0, const int y0, const int z0, const int x1, const int y1, const int z1, const bool border_condition=false) { return crop(x0,y0,z0,0,x1,y1,z1,dim-1,border_condition); } //! Replace the image by a square region of the image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param y0 = Y-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param y1 = Y-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see get_crop() **/ CImg& crop(const int x0, const int y0, const int x1, const int y1, const bool border_condition=false) { return crop(x0,y0,0,0,x1,y1,depth-1,dim-1,border_condition); } //! Replace the image by a square region of the image /** \param x0 = X-coordinate of the upper-left crop rectangle corner. \param x1 = X-coordinate of the lower-right crop rectangle corner. \param border_condition = determine the type of border condition if some of the desired region is outside the image. \see get_crop() **/ CImg& crop(const int x0, const int x1, const bool border_condition=false) { return crop(x0,0,0,0,x1,height-1,depth-1,dim-1,border_condition); } //! Return a set of columns CImg get_columns(const unsigned int x0, const unsigned int x1) const { return get_crop((int)x0,0,0,0,(int)x1,(int)height-1,(int)depth-1,(int)dim-1); } //! Replace the instance image by a set of its columns CImg& columns(const unsigned int x0, const unsigned int x1) { return get_columns(x0,x1).swap(*this); } //! Return one column CImg get_column(const unsigned int x0) const { return get_columns(x0,x0); } //! Replace the instance image by one of its column CImg& column(const unsigned int x0) { return columns(x0,x0); } //! Get a copy of a set of lines of the instance image. CImg get_lines(const unsigned int y0, const unsigned int y1) const { return get_crop(0,(int)y0,0,0,(int)width-1,(int)y1,(int)depth-1,(int)dim-1); } //! Replace the instance image by a set of lines of the instance image. CImg& lines(const unsigned int y0, const unsigned int y1) { return get_lines(y0,y1).swap(*this); } //! Get a copy of a line of the instance image. CImg get_line(const unsigned int y0) const { return get_lines(y0,y0); } //! Replace the instance image by one of its line. CImg& line(const unsigned int y0) { return lines(y0,y0); } //! Get a set of slices CImg get_slices(const unsigned int z0, const unsigned int z1) const { return get_crop(0,0,(int)z0,0,(int)width-1,(int)height-1,(int)z1,(int)dim-1); } // Replace the image by a set of its z-slices CImg& slices(const unsigned int z0, const unsigned int z1) { return get_slices(z0,z1).swap(*this); } //! Get the z-slice \a z of *this, as a new image. CImg get_slice(const unsigned int z0) const { return get_slices(z0,z0); } //! Replace the image by one of its slice. CImg& slice(const unsigned int z0) { return slices(z0,z0); } //! Return a copy of a set of channels of the instance image. CImg get_channels(const unsigned int v0, const unsigned int v1) const { return get_crop(0,0,0,(int)v0,(int)width-1,(int)height-1,(int)depth-1,(int)v1); } //! Replace the instance image by a set of channels of the instance image. CImg& channels(const unsigned int v0, const unsigned int v1) { return get_channels(v0,v1).swap(*this); } //! Return a copy of a channel of the instance image. CImg get_channel(const unsigned int v0) const { return get_channels(v0,v0); } //! Replace the instance image by one of its channel. CImg& channel(const unsigned int v0) { return channels(v0,v0); } //! Get a shared-memory image referencing a set of points of the instance image. CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) { const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim); return CImg(data+beg,x1-x0+1,1,1,1,true); } //! Get a shared-memory image referencing a set of points of the instance image (const version). const CImg get_shared_points(const unsigned int x0, const unsigned int x1, const unsigned int y0=0, const unsigned int z0=0, const unsigned int v0=0) const { const unsigned long beg = offset(x0,y0,z0,v0), end = offset(x1,y0,z0,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_points() : Cannot return a shared-memory subset (%u->%u,%u,%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),x0,x1,y0,z0,v0,width,height,depth,dim); return CImg(data+beg,x1-x0+1,1,1,1,true); } //! Return a shared-memory image referencing a set of lines of the instance image. CImg get_shared_lines(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int v0=0) { const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim); return CImg(data+beg,width,y1-y0+1,1,1,true); } //! Return a shared-memory image referencing a set of lines of the instance image (const version). const CImg get_shared_lines(const unsigned int y0, const unsigned int y1, const unsigned int z0=0, const unsigned int v0=0) const { const unsigned long beg = offset(0,y0,z0,v0), end = offset(0,y1,z0,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_lines() : Cannot return a shared-memory subset (0->%u,%u->%u,%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,y0,y1,z0,v0,width,height,depth,dim); return CImg(data+beg,width,y1-y0+1,1,1,true); } //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image. CImg get_shared_line(const unsigned int y0, const unsigned int z0=0, const unsigned int v0=0) { return get_shared_lines(y0,y0,z0,v0); } //! Return a shared-memory image referencing one particular line (y0,z0,v0) of the instance image (const version). const CImg get_shared_line(const unsigned int y0,const unsigned int z0=0,const unsigned int v0=0) const { return get_shared_lines(y0,y0,z0,v0); } //! Return a shared memory image referencing a set of planes (z0->z1,v0) of the instance image. CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) { const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim); return CImg(data+beg,width,height,z1-z0+1,1,true); } //! Return a shared-memory image referencing a set of planes (z0->z1,v0) of the instance image (const version). const CImg get_shared_planes(const unsigned int z0, const unsigned int z1, const unsigned int v0=0) const { const unsigned long beg = offset(0,0,z0,v0), end = offset(0,0,z1,v0); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_planes() : Cannot return a shared-memory subset (0->%u,0->%u,%u->%u,%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,z0,z1,v0,width,height,depth,dim); return CImg(data+beg,width,height,z1-z0+1,1,true); } //! Return a shared-memory image referencing one plane (z0,v0) of the instance image. CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) { return get_shared_planes(z0,z0,v0); } //! Return a shared-memory image referencing one plane (z0,v0) of the instance image (const version). const CImg get_shared_plane(const unsigned int z0, const unsigned int v0=0) const { return get_shared_planes(z0,z0,v0); } //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image. CImg get_shared_channels(const unsigned int v0, const unsigned int v1) { const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim); return CImg(data+beg,width,height,depth,v1-v0+1,true); } //! Return a shared-memory image referencing a set of channels (v0->v1) of the instance image (const version). const CImg get_shared_channels(const unsigned int v0, const unsigned int v1) const { const unsigned long beg = offset(0,0,0,v0), end = offset(0,0,0,v1); if (beg>end || beg>=size() || end>=size()) throw CImgArgumentException("CImg<%s>::get_shared_channels() : Cannot return a shared-memory subset (0->%u,0->%u,0->%u,%u->%u) from " "a (%u,%u,%u,%u) image.",pixel_type(),width-1,height-1,depth-1,v0,v1,width,height,depth,dim); return CImg(data+beg,width,height,depth,v1-v0+1,true); } //! Return a shared-memory image referencing one channel v0 of the instance image. CImg get_shared_channel(const unsigned int v0) { return get_shared_channels(v0,v0); } //! Return a shared-memory image referencing one channel v0 of the instance image (const version). const CImg get_shared_channel(const unsigned int v0) const { return get_shared_channels(v0,v0); } //! Return a shared version of the instance image. CImg get_shared() { return CImg(data,width,height,depth,dim,true); } //! Return a shared version of the instance image (const version). const CImg get_shared() const { return CImg(data,width,height,depth,dim,true); } //! Mirror an image along the specified axis. /** This is the in-place version of get_mirror(). \sa get_mirror(). **/ CImg& mirror(const char axe='x') { if (!is_empty()) { T *pf,*pb,*buf=0; switch (cimg::uncase(axe)) { case 'x': { pf = ptr(); pb = ptr(width-1); for (unsigned int yzv=0; yzv::mirror() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); } if (buf) delete[] buf; } return *this; } //! Get a mirrored version of the image, along the specified axis. /** \param axe Axe used to mirror the image. Can be \c 'x', \c 'y', \c 'z' or \c 'v'. \sa mirror(). **/ CImg get_mirror(const char axe='x') const { return (+*this).mirror(axe); } //! Translate the image /** This is the in-place version of get_translate(). \sa get_translate(). **/ CImg& translate(const int deltax, const int deltay=0, const int deltaz=0, const int deltav=0, const int border_condition=0) { if (!is_empty()) { if (deltax) // Translate along X-axis switch (border_condition) { case 0: if (cimg::abs(deltax)>=(int)width) return fill(0); if (deltax>0) cimg_forYZV(*this,y,z,k) { std::memmove(ptr(0,y,z,k),ptr(deltax,y,z,k),(width-deltax)*sizeof(T)); std::memset(ptr(width-deltax,y,z,k),0,deltax*sizeof(T)); } else cimg_forYZV(*this,y,z,k) { std::memmove(ptr(-deltax,y,z,k),ptr(0,y,z,k),(width+deltax)*sizeof(T)); std::memset(ptr(0,y,z,k),0,-deltax*sizeof(T)); } break; case 1: if (deltax>0) { const int ndeltax = (deltax>=(int)width)?width-1:deltax; if (!ndeltax) return *this; cimg_forYZV(*this,y,z,k) { std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T)); T *ptrd = ptr(width-1,y,z,k); const T &val = *ptrd; for (int l=0; l=(int)width)?width-1:-deltax; if (!ndeltax) return *this; cimg_forYZV(*this,y,z,k) { std::memmove(ptr(ndeltax,y,z,k),ptr(0,y,z,k),(width-ndeltax)*sizeof(T)); T *ptrd = ptr(0,y,z,k); const T &val = *ptrd; for (int l=0; l0) cimg_forYZV(*this,y,z,k) { std::memcpy(buf,ptr(0,y,z,k),ndeltax*sizeof(T)); std::memmove(ptr(0,y,z,k),ptr(ndeltax,y,z,k),(width-ndeltax)*sizeof(T)); std::memcpy(ptr(width-ndeltax,y,z,k),buf,ndeltax*sizeof(T)); } else cimg_forYZV(*this,y,z,k) { std::memcpy(buf,ptr(width+ndeltax,y,z,k),-ndeltax*sizeof(T)); std::memmove(ptr(-ndeltax,y,z,k),ptr(0,y,z,k),(width+ndeltax)*sizeof(T)); std::memcpy(ptr(0,y,z,k),buf,-ndeltax*sizeof(T)); } delete[] buf; } break; } if (deltay) // Translate along Y-axis switch (border_condition) { case 0: if (cimg::abs(deltay)>=(int)height) return fill(0); if (deltay>0) cimg_forZV(*this,z,k) { std::memmove(ptr(0,0,z,k),ptr(0,deltay,z,k),width*(height-deltay)*sizeof(T)); std::memset(ptr(0,height-deltay,z,k),0,width*deltay*sizeof(T)); } else cimg_forZV(*this,z,k) { std::memmove(ptr(0,-deltay,z,k),ptr(0,0,z,k),width*(height+deltay)*sizeof(T)); std::memset(ptr(0,0,z,k),0,-deltay*width*sizeof(T)); } break; case 1: if (deltay>0) { const int ndeltay = (deltay>=(int)height)?height-1:deltay; if (!ndeltay) return *this; cimg_forZV(*this,z,k) { std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T)); T *ptrd = ptr(0,height-ndeltay,z,k), *ptrs = ptr(0,height-1,z,k); for (int l=0; l=(int)height)?height-1:-deltay; if (!ndeltay) return *this; cimg_forZV(*this,z,k) { std::memmove(ptr(0,ndeltay,z,k),ptr(0,0,z,k),width*(height-ndeltay)*sizeof(T)); T *ptrd = ptr(0,1,z,k), *ptrs = ptr(0,0,z,k); for (int l=0; l0) cimg_forZV(*this,z,k) { std::memcpy(buf,ptr(0,0,z,k),width*ndeltay*sizeof(T)); std::memmove(ptr(0,0,z,k),ptr(0,ndeltay,z,k),width*(height-ndeltay)*sizeof(T)); std::memcpy(ptr(0,height-ndeltay,z,k),buf,width*ndeltay*sizeof(T)); } else cimg_forZV(*this,z,k) { std::memcpy(buf,ptr(0,height+ndeltay,z,k),-ndeltay*width*sizeof(T)); std::memmove(ptr(0,-ndeltay,z,k),ptr(0,0,z,k),width*(height+ndeltay)*sizeof(T)); std::memcpy(ptr(0,0,z,k),buf,-ndeltay*width*sizeof(T)); } delete[] buf; } break; } if (deltaz) // Translate along Z-axis switch (border_condition) { case 0: if (cimg::abs(deltaz)>=(int)depth) return fill(0); if (deltaz>0) cimg_forV(*this,k) { std::memmove(ptr(0,0,0,k),ptr(0,0,deltaz,k),width*height*(depth-deltaz)*sizeof(T)); std::memset(ptr(0,0,depth-deltaz,k),0,width*height*deltaz*sizeof(T)); } else cimg_forV(*this,k) { std::memmove(ptr(0,0,-deltaz,k),ptr(0,0,0,k),width*height*(depth+deltaz)*sizeof(T)); std::memset(ptr(0,0,0,k),0,-deltaz*width*height*sizeof(T)); } break; case 1: if (deltaz>0) { const int ndeltaz = (deltaz>=(int)depth)?depth-1:deltaz; if (!ndeltaz) return *this; cimg_forV(*this,k) { std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T)); T *ptrd = ptr(0,0,depth-ndeltaz,k), *ptrs = ptr(0,0,depth-1,k); for (int l=0; l=(int)depth)?depth-1:-deltaz; if (!ndeltaz) return *this; cimg_forV(*this,k) { std::memmove(ptr(0,0,ndeltaz,k),ptr(0,0,0,k),width*height*(depth-ndeltaz)*sizeof(T)); T *ptrd = ptr(0,0,1,k), *ptrs = ptr(0,0,0,k); for (int l=0; l0) cimg_forV(*this,k) { std::memcpy(buf,ptr(0,0,0,k),width*height*ndeltaz*sizeof(T)); std::memmove(ptr(0,0,0,k),ptr(0,0,ndeltaz,k),width*height*(depth-ndeltaz)*sizeof(T)); std::memcpy(ptr(0,0,depth-ndeltaz,k),buf,width*height*ndeltaz*sizeof(T)); } else cimg_forV(*this,k) { std::memcpy(buf,ptr(0,0,depth+ndeltaz,k),-ndeltaz*width*height*sizeof(T)); std::memmove(ptr(0,0,-ndeltaz,k),ptr(0,0,0,k),width*height*(depth+ndeltaz)*sizeof(T)); std::memcpy(ptr(0,0,0,k),buf,-ndeltaz*width*height*sizeof(T)); } delete[] buf; } break; } if (deltav) // Translate along V-axis switch (border_condition) { case 0: if (cimg::abs(deltav)>=(int)dim) return fill(0); if (deltav>0) { std::memmove(data,ptr(0,0,0,deltav),width*height*depth*(dim-deltav)*sizeof(T)); std::memset(ptr(0,0,0,dim-deltav),0,width*height*depth*deltav*sizeof(T)); } else cimg_forV(*this,k) { std::memmove(ptr(0,0,0,-deltav),data,width*height*depth*(dim+deltav)*sizeof(T)); std::memset(data,0,-deltav*width*height*depth*sizeof(T)); } break; case 1: if (deltav>0) { const int ndeltav = (deltav>=(int)dim)?dim-1:deltav; if (!ndeltav) return *this; std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T)); T *ptrd = ptr(0,0,0,dim-ndeltav), *ptrs = ptr(0,0,0,dim-1); for (int l=0; l=(int)dim)?dim-1:-deltav; if (!ndeltav) return *this; std::memmove(ptr(0,0,0,ndeltav),data,width*height*depth*(dim-ndeltav)*sizeof(T)); T *ptrd = ptr(0,0,0,1); for (int l=0; l0) { std::memcpy(buf,data,width*height*depth*ndeltav*sizeof(T)); std::memmove(data,ptr(0,0,0,ndeltav),width*height*depth*(dim-ndeltav)*sizeof(T)); std::memcpy(ptr(0,0,0,dim-ndeltav),buf,width*height*depth*ndeltav*sizeof(T)); } else { std::memcpy(buf,ptr(0,0,0,dim+ndeltav),-ndeltav*width*height*depth*sizeof(T)); std::memmove(ptr(0,0,0,-ndeltav),data,width*height*depth*(dim+ndeltav)*sizeof(T)); std::memcpy(data,buf,-ndeltav*width*height*depth*sizeof(T)); } delete[] buf; } break; } } return *this; } //! Return a translated image. /** \param deltax Amount of displacement along the X-axis. \param deltay Amount of displacement along the Y-axis. \param deltaz Amount of displacement along the Z-axis. \param deltav Amount of displacement along the V-axis. \param border_condition Border condition. - \c border_condition can be : - 0 : Zero border condition (Dirichlet). - 1 : Nearest neighbors (Neumann). - 2 : Repeat Pattern (Fourier style). **/ CImg get_translate(const int deltax,const int deltay=0,const int deltaz=0,const int deltav=0, const int border_condition=0) const { return (+*this).translate(deltax,deltay,deltaz,deltav,border_condition); } //! Return a 2D representation of a 3D image, with three slices. CImg get_projections2d(const unsigned int px0,const unsigned int py0,const unsigned int pz0) const { if (is_empty()) return CImg(); const unsigned int x0=(px0>=width)?width-1:px0, y0=(py0>=height)?height-1:py0, z0=(pz0>=depth)?depth-1:pz0; CImg res(width+depth,height+depth,1,dim); res.fill((*this)[0]); { cimg_forXYV(*this,x,y,k) res(x,y,0,k) = (*this)(x,y,z0,k); } { cimg_forYZV(*this,y,z,k) res(width+z,y,0,k) = (*this)(x0,y,z,k); } { cimg_forXZV(*this,x,z,k) res(x,height+z,0,k) = (*this)(x,y0,z,k); } return res; } //! Return the image histogram. /** The histogram H of an image I is a 1D-function where H(x) is the number of occurences of the value x in I. \param nblevels = Number of different levels of the computed histogram. For classical images, this value is 256 (default value). You should specify more levels if you are working with CImg or images with high range of pixel values. \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min won't be counted. \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max won't be counted. \note If val_min==val_max==0 (default values), the function first estimates the minimum and maximum pixel values of the current image, then uses these values for the histogram computation. \result The histogram is returned as a 1D CImg image H, having a size of (nblevels,1,1,1) such that H(0) and H(nblevels-1) are respectively equal to the number of occurences of the values val_min and val_max in I. \note Histogram computation always returns a 1D function. Histogram of multi-valued (such as color) images are not multi-dimensional. \see get_equalize_histogram(), equalize_histogram() **/ CImg get_histogram(const unsigned int nblevels=256, const T val_min=(T)0, const T val_max=(T)0) const { if (is_empty()) return CImg(); if (!nblevels) throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with 0 levels", pixel_type()); T vmin = val_min, vmax = val_max; CImg res(nblevels,1,1,1,0); if (vmin>=vmax && vmin==0) { const CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; } if (vmin=0 && pos<(int)nblevels) res[pos]++; } else res[0]+=size(); return res; } //! Equalize the image histogram /** This is the in-place version of \ref get_equalize_histogram() **/ CImg& equalize_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) { if (!is_empty()) { T vmin = val_min, vmax = val_max; if (vmin==vmax && vmin==0) { const CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; } if (vmin hist = get_histogram(nblevels,vmin,vmax); float cumul = 0; cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos]=cumul; } cimg_for(*this,ptr,T) { const int pos = (unsigned int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); if (pos>=0 && pos<(int)nblevels) *ptr = (T)(vmin + (vmax-vmin)*hist[pos]/size()); } } } return *this; } //! Return the histogram-equalized version of the current image. /** The histogram equalization is a classical image processing algorithm that enhances the image contrast by expanding its histogram. \param nblevels = Number of different levels of the computed histogram. For classical images, this value is 256 (default value). You should specify more levels if you are working with CImg or images with high range of pixel values. \param val_min = Minimum value considered for the histogram computation. All pixel values lower than val_min won't be changed. \param val_max = Maximum value considered for the histogram computation. All pixel values higher than val_max won't be changed. \note If val_min==val_max==0 (default values), the function acts on all pixel values of the image. \return A new image with same size is returned, where pixels have been equalized. \see get_histogram(), equalize_histogram() **/ CImg get_equalize_histogram(const unsigned int nblevels=256,const T val_min=(T)0,const T val_max=(T)0) const { return (+*this).equalize_histogram(nblevels,val_min,val_max); } //! Return the scalar image of vector norms. /** When dealing with vector-valued images (i.e images with dimv()>1), this function computes the L1,L2 or Linf norm of each vector-valued pixel. \param norm_type = Type of the norm being computed (1 = L1, 2 = L2, -1 = Linf). \return A scalar-valued image CImg with size (dimx(),dimy(),dimz(),1), where each pixel is the norm of the corresponding pixels in the original vector-valued image. \see get_orientation_pointwise, orientation_pointwise, norm_pointwise. **/ CImg::type> get_norm_pointwise(int norm_type=2) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); CImg res(width,height,depth); switch(norm_type) { case -1: { // Linf norm cimg_forXYZ(*this,x,y,z) { restype n=0; cimg_forV(*this,v) { const restype tmp = (restype)cimg::abs((*this)(x,y,z,v)); if (tmp>n) n=tmp; res(x,y,z) = n; } } } break; case 1: { // L1 norm cimg_forXYZ(*this,x,y,z) { restype n=0; cimg_forV(*this,v) n+=cimg::abs((*this)(x,y,z,v)); res(x,y,z) = n; } } break; default: { // L2 norm cimg_forXYZ(*this,x,y,z) { restype n=0; cimg_forV(*this,v) n+=(*this)(x,y,z,v)*(*this)(x,y,z,v); res(x,y,z) = (restype)std::sqrt((double)n); } } break; } return res; } //! Replace each pixel value with its vector norm. /** This is the in-place version of \ref get_norm_pointwise(). \note Be careful when using this function on CImg with T=char, unsigned char,unsigned int or int. The vector norm is usually a floating point value, and a rough cast will be done here. **/ CImg& norm_pointwise(int norm_type=2) { return CImg(get_norm_pointwise(norm_type)).swap(*this); } //! Return the image of normalized vectors /** When dealing with vector-valued images (i.e images with dimv()>1), this function return the image of normalized vectors (unit vectors). Null vectors are unchanged. The L2-norm is computed for the normalization. \return A new vector-valued image with same size, where each vector-valued pixels have been normalized. \see get_norm_pointwise, norm_pointwise, orientation_pointwise. **/ CImg::type> get_orientation_pointwise() const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); return CImg(*this,false).orientation_pointwise(); } //! Replace each pixel value by its normalized vector /** This is the in-place version of \ref get_orientation_pointwise() **/ CImg& orientation_pointwise() { cimg_forXYZ(*this,x,y,z) { float n = 0.0f; cimg_forV(*this,v) n+=(float)((*this)(x,y,z,v)*(*this)(x,y,z,v)); n = (float)std::sqrt(n); if (n>0) cimg_forV(*this,v) (*this)(x,y,z,v)=(T)((*this)(x,y,z,v)/n); else cimg_forV(*this,v) (*this)(x,y,z,v)=0; } return *this; } //! Split image into a list CImgList<>. CImgList get_split(const char axe='x', const unsigned int nb=0) const { if (is_empty()) return CImgList(); CImgList res; switch (cimg::uncase(axe)) { case 'x': { if (nb>width) throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'x' into %u images.", pixel_type(),width,height,depth,dim,data,nb); res.assign(nb?nb:width); const unsigned int delta = width/res.size + ((width%res.size)?1:0); unsigned int l,x; for (l=0, x=0; lheight) throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'y' into %u images.", pixel_type(),width,height,depth,dim,data,nb); res.assign(nb?nb:height); const unsigned int delta = height/res.size + ((height%res.size)?1:0); unsigned int l,x; for (l=0, x=0; ldepth) throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'z' into %u images.", pixel_type(),width,height,depth,dim,data,nb); res.assign(nb?nb:depth); const unsigned int delta = depth/res.size + ((depth%res.size)?1:0); unsigned int l,x; for (l=0, x=0; ldim) throw CImgArgumentException("CImg<%s>::get_split() : Cannot split instance image (%u,%u,%u,%u,%p) along 'v' into %u images.", pixel_type(),width,height,depth,dim,data,nb); res.assign(nb?nb:dim); const unsigned int delta = dim/res.size + ((dim%res.size)?1:0); unsigned int l,x; for (l=0, x=0; l::get_split() : Unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); break; } return res; } //! Append an image to another one CImg get_append(const CImg& img, const char axis='x', const char align='c') const { if (!img) return *this; if (is_empty()) return img; CImgList temp(2); temp[0].width = width; temp[0].height = height; temp[0].depth = depth; temp[0].dim = dim; temp[0].data = data; temp[1].width = img.width; temp[1].height = img.height; temp[1].depth = img.depth; temp[1].dim = img.dim; temp[1].data = img.data; const CImg res = temp.get_append(axis,align); temp[0].width = temp[0].height = temp[0].depth = temp[0].dim = 0; temp[0].data = 0; temp[1].width = temp[1].height = temp[1].depth = temp[1].dim = 0; temp[1].data = 0; return res; } //! Append an image to another one (in-place version) CImg& append(const CImg& img, const char axis='x', const char align='c') { if (!img) return *this; if (is_empty()) return (*this=img); return get_append(img,axis,align).swap(*this); } //! Return a list of images, corresponding to the XY-gradients of an image. /** \param scheme = Numerical scheme used for the gradient computation : - -1 = Backward finite differences - 0 = Centered finite differences - 1 = Forward finite differences - 2 = Using Sobel masks - 3 = Using rotation invariant masks - 4 = Using Deriche recusrsive filter. **/ CImgList::type> get_gradientXY(const int scheme=0) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImgList(2); CImgList res(2,width,height,depth,dim); switch(scheme) { case -1: { // backward finite differences CImg_3x3(I,restype); cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = Icc-Ipc; res[1](x,y,z,k) = Icc-Icp; } } break; case 1: { // forward finite differences CImg_2x2(I,restype); cimg_forZV(*this,z,k) cimg_for2x2(*this,x,y,z,k,I) { res[0](x,y,0,k) = Inc-Icc; res[1](x,y,z,k) = Icn-Icc; } } break; case 2: { // using Sobel mask CImg_3x3(I,restype); const float a = 1, b = 2; cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn; res[1](x,y,z,k) = -a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn; } } break; case 3: { // using rotation invariant mask CImg_3x3(I,restype); const float a = (float)(0.25*(2-std::sqrt(2.0))), b = (float)(0.5f*(std::sqrt(2.0)-1)); cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = -a*Ipp-b*Ipc-a*Ipn+a*Inp+b*Inc+a*Inn; res[1](x,y,z,k) = -a*Ipp-b*Icp-a*Inp+a*Ipn+b*Icn+a*Inn; } } break; case 4: { // using Deriche filter with low standard variation res[0] = get_deriche(0,1,'x'); res[1] = get_deriche(0,1,'y'); } break; default: { // central finite differences CImg_3x3(I,restype); cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = 0.5f*(Inc-Ipc); res[1](x,y,z,k) = 0.5f*(Icn-Icp); } } break; } return res; } //! Return a list of images, corresponding to the XYZ-gradients of an image. /** \see get_gradientXY(). **/ CImgList::type> get_gradientXYZ(const int scheme=0) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImgList(3); CImgList res(3,width,height,depth,dim); CImg_3x3x3(I,restype); switch(scheme) { case -1: { // backward finite differences cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = Iccc-Ipcc; res[1](x,y,z,k) = Iccc-Icpc; res[2](x,y,z,k) = Iccc-Iccp; } } break; case 1: { // forward finite differences cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = Incc-Iccc; res[1](x,y,z,k) = Icnc-Iccc; res[2](x,y,z,k) = Iccn-Iccc; } } break; case 4: { // using Deriche filter with low standard variation res[0] = get_deriche(0,1,'x'); res[1] = get_deriche(0,1,'y'); res[2] = get_deriche(0,1,'z'); } break; default: { // central finite differences cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { res[0](x,y,z,k) = 0.5f*(Incc-Ipcc); res[1](x,y,z,k) = 0.5f*(Icnc-Icpc); res[2](x,y,z,k) = 0.5f*(Iccn-Iccp); } } break; } return res; } //! Return the 2D structure tensor field of an image CImg::type> get_structure_tensorXY(const int scheme=1) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); CImg res(width,height,depth,3,0); CImg_3x3(I,restype); switch (scheme) { case 0: { // classical central finite differences cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,0,k,I) { const restype ix = 0.5f*(Inc-Ipc), iy = 0.5f*(Icn-Icp); res(x,y,z,0)+=ix*ix; res(x,y,z,1)+=ix*iy; res(x,y,z,2)+=iy*iy; } } break; default: { // Precise forward/backward finite differences cimg_forZV(*this,z,k) cimg_for3x3(*this,x,y,0,k,I) { const restype ixf = Inc-Icc, ixb = Icc-Ipc, iyf = Icn-Icc, iyb = Icc-Icp; res(x,y,z,0) += 0.5f*(ixf*ixf+ixb*ixb); res(x,y,z,1) += 0.25f*(ixf*iyf+ixf*iyb+ixb*iyf+ixb*iyb); res(x,y,z,2) += 0.5f*(iyf*iyf+iyb*iyb); } } break; } return res; } //! In-place version of the previous function CImg& structure_tensorXY(const int scheme=1) { return assign(get_structure_tensorXY(scheme)); } //! Return the 3D structure tensor field of an image CImg::type> get_structure_tensorXYZ(const int scheme=1) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); CImg res(width,height,depth,6,0); CImg_3x3x3(I,restype); switch (scheme) { case 0: { // classical central finite differences cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { const restype ix = 0.5f*(Incc-Ipcc), iy = 0.5f*(Icnc-Icpc), iz = 0.5f*(Iccn-Iccp); res(x,y,z,0)+=ix*ix; res(x,y,z,1)+=ix*iy; res(x,y,z,2)+=ix*iz; res(x,y,z,3)+=iy*iy; res(x,y,z,4)+=iy*iz; res(x,y,z,5)+=iz*iz; } } break; default: { // Precise forward/backward finite differences cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { const restype ixf = Incc-Iccc, ixb = Iccc-Ipcc, iyf = Icnc-Iccc, iyb = Iccc-Icpc, izf = Iccn-Iccc, izb = Iccc-Iccp; res(x,y,z,0) += 0.5f*(ixf*ixf + ixb*ixb); res(x,y,z,1) += 0.25f*(ixf*iyf + ixf*iyb + ixb*iyf + ixb*iyb); res(x,y,z,2) += 0.25f*(ixf*izf + ixf*izb + ixb*izf + ixb*izb); res(x,y,z,3) += 0.5f*(iyf*iyf + iyb*iyb); res(x,y,z,4) += 0.25f*(iyf*izf + iyf*izb + iyb*izf + iyb*izb); res(x,y,z,5) += 0.5f*(izf*izf + izb*izb); } } break; } return res; } //! In-place version of the previous function CImg& structure_tensorXYZ(const int scheme=1) { return assign(get_structure_tensorXYZ(scheme)); } //! Get distance function from 0-valued isophotes by the application of the eikonal equation. CImg::type> get_distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) const { typedef typename cimg::largest::type ftype; return CImg(*this).distance_function(nb_iter,band_size,precision); } //! In-place version of the previous function CImg& distance_function(const unsigned int nb_iter=100, const float band_size=0.0f, const float precision=0.5f) { typedef typename cimg::largest::type ftype; if (is_empty()) return *this; CImg veloc(*this); for (unsigned int iter=0; iter1) { // 3D version CImg_3x3x3(I,ftype); cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) if (band_size<=0 || cimg::abs(Iccc)0?Incc-Iccc:Iccc-Ipcc, iy = gy*sgn>0?Icnc-Iccc:Iccc-Icpc, iz = gz*sgn>0?Iccn-Iccc:Iccc-Iccp, ng = 1e-5f+(ftype)std::sqrt(gx*gx+gy*gy+gz*gz), ngx = gx/ng, ngy = gy/ng, ngz = gz/ng; veloc(x,y,z,k) = sgn*(ngx*ix+ngy*iy+ngz*iz-1); } } else { // 2D version CImg_3x3(I,ftype); cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) if (band_size<=0 || cimg::abs(Icc)0?Inc-Icc:Icc-Ipc, iy = gy*sgn>0?Icn-Icc:Icc-Icp, ng = 1e-5f+(ftype)std::sqrt(gx*gx+gy*gy), ngx = gx/ng, ngy = gy/ng; veloc(x,y,k) = sgn*(ngx*ix+ngy*iy-1); } } const CImgStats stats(veloc,false); const float xdt = precision/(float)cimg::max(cimg::abs(stats.min),cimg::abs(stats.max)); *this+=(veloc*=xdt); } return *this; } //@} //------------------------------------- // //! \name Meshes and Triangulations //@{ //------------------------------------- struct _marching_squares_func { const CImg& ref; _marching_squares_func(const CImg& pref):ref(pref) {} float operator()(const float x, const float y) const { return (float)ref((int)x,(int)y); } }; struct _marching_cubes_func { const CImg& ref; _marching_cubes_func(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z) const { return (float)ref((int)x,(int)y,(int)z); } }; struct _marching_squares_func_float { const CImg& ref; _marching_squares_func_float(const CImg& pref):ref(pref) {} float operator()(const float x, const float y) const { return (float)ref.linear_pix2d(x,y); } }; struct _marching_cubes_func_float { const CImg& ref; _marching_cubes_func_float(const CImg& pref):ref(pref) {} float operator()(const float x, const float y, const float z) const { return (float)ref.linear_pix3d(x,y,z); } }; //! Get a vectorization of an implicit function defined by the instance image. template const CImg& marching_squares(const float isovalue,CImgList& points, CImgList& primitives) const { if (height<=1 || depth>1 || dim>1) throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.", pixel_type(),width,height,depth,dim,data); const _marching_squares_func func(*this); cimg::marching_squares(func,isovalue,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,1.0f,1.0f,points,primitives); return *this; } //! Get a vectorization of an implicit function defined by the instance image. /** This version allows to specify the marching squares resolution along x,y, and z. **/ template const CImg& marching_squares(const float isovalue, const float resx, const float resy, CImgList& points, CImgList& primitives) const { if (height<=1 || depth>1 || dim>1) throw CImgInstanceException("CImg<%s>::marching_squares() : Instance image (%u,%u,%u,%u,%p) is not a 2D scalar image.", pixel_type(),width,height,depth,dim,data); const _marching_squares_func_float func(*this); cimg::marching_squares(func,isovalue,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,resx,resy,points,primitives); return *this; } //! Get a triangulation of an implicit function defined by the instance image template const CImg& marching_cubes(const float isovalue,CImgList& points, CImgList& primitives, const bool invert_faces = false) const { if (depth<=1 || dim>1) throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.", pixel_type(),width,height,depth,dim,data); const _marching_cubes_func func(*this); cimg::marching_cubes(func,isovalue,0.0f,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f, 1.0f,1.0f,1.0f,points,primitives,invert_faces); return *this; } //! Get a triangulation of an implicit function defined by the instance image /** This version allows to specify the marching cube resolution along x,y and z. **/ template const CImg& marching_cubes(const float isovalue, const float resx, const float resy, const float resz, CImgList& points, CImgList& primitives, const bool invert_faces = false) const { if (depth<=1 || dim>1) throw CImgInstanceException("CImg<%s>::marching_cubes() : Instance image (%u,%u,%u,%u,%p) is not a 3D scalar image.", pixel_type(),width,height,depth,dim,data); const _marching_cubes_func_float func(*this); cimg::marching_cubes(func,isovalue,0.0f,0.0f,0.0f,dimx()-1.0f,dimy()-1.0f,dimz()-1.0f, resx,resy,resz,points,primitives,invert_faces); return *this; } //@} //---------------------------- // //! \name Color conversions //@{ //---------------------------- //! Return the default 256 colors palette. /** The default color palette is used by %CImg when displaying images on 256 colors displays. It consists in the quantification of the (R,G,B) color space using 3:3:2 bits for color coding (i.e 8 levels for the Red and Green and 4 levels for the Blue). \return A 256x1x1x3 color image defining the palette entries. **/ static CImg get_default_LUT8() { static CImg palette; if (!palette.data) { palette.assign(256,1,1,3); for (unsigned int index=0, r=16; r<256; r+=32) for (unsigned int g=16; g<256; g+=32) for (unsigned int b=32; b<256; b+=64) { palette(index,0) = r; palette(index,1) = g; palette(index++,2) = b; } } return palette; } //! Convert color pixels from (R,G,B) to match a specified palette. /** This function return a (R,G,B) image where colored pixels are constrained to match entries of the specified color \c palette. \param palette User-defined palette that will constraint the color conversion. \param dithering Enable/Disable Floyd-Steinberg dithering. \param indexing If \c true, each resulting image pixel is an index to the given color palette. Otherwise, (R,G,B) values of the palette are copied instead. **/ template CImg get_RGBtoLUT(const CImg& palette, const bool dithering=true,const bool indexing=false) const { if (is_empty()) return CImg(); if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoLUT() : Input image dimension is dim=%u, " "should be a (R,G,B) image.",pixel_type(),dim); if (palette.data && palette.dim!=3) throw CImgArgumentException("CImg<%s>::RGBtoLUT() : Given palette dimension is dim=%u, " "should be a (R,G,B) palette",pixel_type(),palette.dim); CImg res(width,height,depth,indexing?1:3), pal = palette.data?palette:CImg::get_default_LUT8(); float *line1 = new float[3*width], *line2 = new float[3*width], *pline1 = line1, *pline2 = line2; cimg_forZ(*this,z) { float *ptr=pline2; cimg_forX(*this,x) { *(ptr++)=(*this)(x,0,z,0); *(ptr++)=(*this)(x,0,z,1); *(ptr++)=(*this)(x,0,z,2); } cimg_forY(*this,y) { cimg::swap(pline1,pline2); if (y255?255:R); G = G<0?0:(G>255?255:G); B = B<0?0:(B>255?255:B); int best_index = 0; t Rbest=0,Gbest=0,Bbest=0; if (palette.data) { // find best match in given color palette float min = cimg::type::max(); cimg_forX(palette,off) { const t Rp = palette(off,0), Gp = palette(off,1), Bp = palette(off,2); const float error = (float)((Rp-R)*(Rp-R) + (Gp-G)*(Gp-G) + (Bp-B)*(Bp-B)); if (error>3) | ((unsigned char)Bbest>>6); } if (indexing) res(x,y,z) = best_index; else { res(x,y,z,0) = Rbest; res(x,y,z,1) = Gbest; res(x,y,z,2) = Bbest; } if (dithering) { // apply dithering to neighborhood pixels if needed const float dR = (float)(R-Rbest), dG = (float)(G-Gbest), dB = (float)(B-Bbest); if (x0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; } if (x get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const { CImg foo; return get_RGBtoLUT(foo,dithering,indexing); } //! Convert color pixels from (R,G,B) to match the specified color palette. /** This is the in-place version of get_RGBtoLUT(). **/ CImg& RGBtoLUT(const CImg& palette,const bool dithering=true,const bool indexing=false) { return get_RGBtoLUT(palette,dithering,indexing).swap(*this); } //! Convert color pixels from (R,G,B) to match the specified color palette. /** This is the in-place version of get_RGBtoLUT(). **/ CImg& RGBtoLUT(const bool dithering=true,const bool indexing=false) { CImg foo; return get_RGBtoLUT(foo,dithering,indexing).swap(*this); } //! Convert an indexed image to a (R,G,B) image using the specified color palette. template CImg get_LUTtoRGB(const CImg& palette) const { if (is_empty()) return CImg(); if (dim!=1) throw CImgInstanceException("CImg<%s>::LUTtoRGB() : Input image dimension is dim=%u, " "should be a LUT image",pixel_type(),dim); if (palette.data && palette.dim!=3) throw CImgArgumentException("CImg<%s>::LUTtoRGB() : Given palette dimension is dim=%u, " "should be a (R,G,B) palette",pixel_type(),palette.dim); CImg res(width,height,depth,3); CImg pal = palette.data?palette:get_default_LUT8(); cimg_forXYZ(*this,x,y,z) { const unsigned int index = (unsigned int)(*this)(x,y,z); res(x,y,z,0) = pal(index,0); res(x,y,z,1) = pal(index,1); res(x,y,z,2) = pal(index,2); } return res; } //! Convert an indexed image (with the default palette) to a (R,G,B) image. CImg get_LUTtoRGB() const { CImg foo; return get_LUTtoRGB(foo); } //! In-place version of get_LUTtoRGB(). CImg& LUTtoRGB(const CImg& palette) { return get_LUTtoRGB(palette).swap(*this); } //! In-place version of get_LUTroRGB(). CImg& LUTtoRGB() { CImg foo; return get_LUTtoRGB(foo).swap(*this); } //! Convert color pixels from (R,G,B) to (H,S,V). CImg& RGBtoHSV() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoHSV() : Input image dimension is dim=%u, " "should be a (R,G,B) image.",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const float R = (float)((*this)(x,y,z,0)/255.0f), G = (float)((*this)(x,y,z,1)/255.0f), B = (float)((*this)(x,y,z,2)/255.0f); const float m = cimg::min(R,G,B), v = cimg::max(R,G,B); float h,s; if (v==m) { h=-1; s=0; } else { const float f = (R==m)?(G-B):((G==m)?(B-R):(R-G)), i = (R==m)?3.0f:((G==m)?5.0f:1.0f); h = (i-f/(v-m)); s = (v-m)/v; if (h>=6.0f) h-=6.0f; h*=(float)cimg::PI/3.0f; } (*this)(x,y,z,0) = (T)h; (*this)(x,y,z,1) = (T)s; (*this)(x,y,z,2) = (T)v; } } return *this; } //! Convert color pixels from (H,S,V) to (R,G,B). CImg& HSVtoRGB() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::HSVtoRGB() : Input image dimension is dim=%u, " "should be a (H,S,V) image",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { float H = (float)((*this)(x,y,z,0)), S = (float)((*this)(x,y,z,1)), V = (float)((*this)(x,y,z,2)); float R=0,G=0,B=0; if (H<0) R=G=B=V; else { H/=(float)cimg::PI/3.0f; const int i = (int)std::floor(H); const float f = (i&1)?(H-i):(1.0f-H+i), m = V*(1.0f-S), n = V*(1.0f-S*f); switch(i) { case 6: case 0: R=V; G=n; B=m; break; case 1: R=n; G=V; B=m; break; case 2: R=m; G=V; B=n; break; case 3: R=m; G=n; B=V; break; case 4: R=n; G=m; B=V; break; case 5: R=V; G=m; B=n; break; } } (*this)(x,y,z,0) = (T)(R*255.0f); (*this)(x,y,z,1) = (T)(G*255.0f); (*this)(x,y,z,2) = (T)(B*255.0f); } } return *this; } //! Convert color pixels from (R,G,B) to (Y,Cb,Cr)_8 (Thanks to Chen Wang). CImg& RGBtoYCbCr() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYCbCr() : Input image dimension is dim=%u, " "should be a (R,G,B) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const int R = (int)((*this)(x,y,z,0)), G = (int)((*this)(x,y,z,1)), B = (int)((*this)(x,y,z,2)); const int Y = ((66*R+129*G+25*B+128)>>8) + 16, Cb = ((-38*R-74*G+112*B+128)>>8) + 128, Cr = ((112*R-94*G-18*B+128)>>8) + 128; (*this)(x,y,z,0) = (T)(Y<0?0:(Y>255?255:Y)); (*this)(x,y,z,1) = (T)(Cb<0?0:(Cb>255?255:Cb)); (*this)(x,y,z,2) = (T)(Cr<0?0:(Cr>255?255:Cr)); } } return *this; } //! Convert color pixels from (Y,Cb,Cr)_8 to (R,G,B). CImg& YCbCrtoRGB() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::YCbCrtoRGB() : Input image dimension is dim=%u, " "should be a (Y,Cb,Cr)_8 image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const int Y = (int)((*this)(x, y, z, 0)-16), Cb = (int)((*this)(x, y, z, 1)-128), Cr = (int)((*this)(x, y, z, 2)-128); const int R = ((298*Y + 409*Cr + 128) >> 8 ), G = ((298*Y - 100*Cb - 208*Cr + 128) >> 8 ), B = ((298*Y + 516*Cb + 128) >> 8 ); (*this)(x,y,z,0) = (T)(R<0?0:(R>255?255:R)); (*this)(x,y,z,1) = (T)(G<0?0:(G>255?255:G)); (*this)(x,y,z,2) = (T)(B<0?0:(B>255?255:B)); } } return *this; } //! Convert color pixels from (R,G,B) to (Y,U,V). CImg& RGBtoYUV() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoYUV() : Input image dimension is dim=%u, " "should be a (R,G,B) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const float R = (*this)(x,y,z,0)/255.0f, G = (*this)(x,y,z,1)/255.0f, B = (*this)(x,y,z,2)/255.0f, Y = (T)(0.299*R + 0.587*G + 0.114*B); (*this)(x,y,z,0) = (T)Y; (*this)(x,y,z,1) = (T)(0.492*(B-Y)); (*this)(x,y,z,2) = (T)(0.877*(R-Y)); } } return *this; } //! Convert color pixels from (Y,U,V) to (R,G,B). CImg& YUVtoRGB() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::YUVtoRGB() : Input image dimension is dim=%u, " "should be a (Y,U,V) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const T Y = (*this)(x,y,z,0), U = (*this)(x,y,z,1), V = (*this)(x,y,z,2); (*this)(x,y,z,0) = (T)((Y + 1.140*V)*255.0f); (*this)(x,y,z,1) = (T)((Y - 0.395*U - 0.581*V)*255.0f); (*this)(x,y,z,2) = (T)((Y + 2.032*U)*255.0f); } } return *this; } //! Convert color pixels from (R,G,B) to (X,Y,Z)_709. CImg& RGBtoXYZ() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::RGBtoXYZ() : Input image dimension is dim=%u, " "should be a (R,G,B) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const float R = (float)((*this)(x,y,z,0)/255.0f), G = (float)((*this)(x,y,z,1)/255.0f), B = (float)((*this)(x,y,z,2)/255.0f); (*this)(x,y,z,0) = (T)(0.412453*R + 0.357580*G + 0.180423*B); (*this)(x,y,z,1) = (T)(0.212671*R + 0.715160*G + 0.072169*B); (*this)(x,y,z,2) = (T)(0.019334*R + 0.119193*G + 0.950227*B); } } return *this; } //! Convert (X,Y,Z)_709 pixels of a color image into the (R,G,B) color space. CImg& XYZtoRGB() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoRGB() : Input image dimension is dim=%u, " "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const float X = (float)(255.0f*(*this)(x,y,z,0)), Y = (float)(255.0f*(*this)(x,y,z,1)), Z = (float)(255.0f*(*this)(x,y,z,2)); (*this)(x,y,z,0) = (T)(3.240479*X - 1.537150*Y - 0.498535*Z); (*this)(x,y,z,1) = (T)(-0.969256*X + 1.875992*Y + 0.041556*Z); (*this)(x,y,z,2) = (T)(0.055648*X - 0.204043*Y + 1.057311*Z); } } return *this; } //! Convert (X,Y,Z)_709 pixels of a color image into the (L*,a*,b*) color space. #define cimg_Labf(x) ((x)>=0.008856?(std::pow(x,1/3.0)):(7.787*(x)+16.0/116.0)) #define cimg_Labfi(x) ((x)>=0.206893?((x)*(x)*(x)):(((x)-16.0/116.0)/7.787)) CImg& XYZtoLab() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoLab() : Input image dimension is dim=%u, " "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); const double Xn = 0.412453 + 0.357580 + 0.180423, Yn = 0.212671 + 0.715160 + 0.072169, Zn = 0.019334 + 0.119193 + 0.950227; cimg_forXYZ(*this,x,y,z) { const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2); const double XXn = X/Xn, YYn = Y/Yn, ZZn = Z/Zn, fX = cimg_Labf(XXn), fY = cimg_Labf(YYn), fZ = cimg_Labf(ZZn); (*this)(x,y,z,0) = (T)(116*fY-16); (*this)(x,y,z,1) = (T)(500*(fX-fY)); (*this)(x,y,z,2) = (T)(200*(fY-fZ)); } } return *this; } //! Convert (L,a,b) pixels of a color image into the (X,Y,Z) color space. CImg& LabtoXYZ() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::LabtoXYZ() : Input image dimension is dim=%u, " "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); const double Xn = 0.412453 + 0.357580 + 0.180423, Yn = 0.212671 + 0.715160 + 0.072169, Zn = 0.019334 + 0.119193 + 0.950227; cimg_forXYZ(*this,x,y,z) { const T L = (*this)(x,y,z,0), a = (*this)(x,y,z,1), b = (*this)(x,y,z,2); const double cY = (L+16)/116.0, Y = Yn*cimg_Labfi(cY), pY = std::pow(Y/Yn,1.0/3), cX = a/500+pY, X = Xn*cX*cX*cX, cZ = pY-b/200, Z = Zn*cZ*cZ*cZ; (*this)(x,y,z,0) = (T)(X); (*this)(x,y,z,1) = (T)(Y); (*this)(x,y,z,2) = (T)(Z); } } return *this; } //! Convert (X,Y,Z)_709 pixels of a color image into the (x,y,Y) color space. CImg& XYZtoxyY() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::XYZtoxyY() : Input image dimension is dim=%u, " "should be a (X,Y,Z) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const T X = (*this)(x,y,z,0), Y = (*this)(x,y,z,1), Z = (*this)(x,y,z,2), sum = (X+Y+Z), nsum = sum>0?sum:1; (*this)(x,y,z,0) = X/nsum; (*this)(x,y,z,1) = Y/nsum; (*this)(x,y,z,2) = Y; } } return *this; } //! Convert (x,y,Y) pixels of a color image into the (X,Y,Z)_709 color space. CImg& xyYtoXYZ() { if (!is_empty()) { if (dim!=3) throw CImgInstanceException("CImg<%s>::xyYtoXYZ() : Input image dimension is dim=%u, " "should be a (x,y,Y) image (dim=3)",pixel_type(),dim); cimg_forXYZ(*this,x,y,z) { const T px = (*this)(x,y,z,0), py = (*this)(x,y,z,1), Y = (*this)(x,y,z,2), ny = py>0?py:1; (*this)(x,y,z,0) = (T)(px*Y/ny); (*this)(x,y,z,1) = Y; (*this)(x,y,z,2) = (T)((1-px-py)*Y/ny); } } return *this; } //! In-place version of get_RGBtoLab(). CImg& RGBtoLab() { return RGBtoXYZ().XYZtoLab(); } //! In-place version of get_LabtoRGb(). CImg& LabtoRGB() { return LabtoXYZ().XYZtoRGB(); } //! In-place version of get_RGBtoxyY(). CImg& RGBtoxyY() { return RGBtoXYZ().XYZtoxyY(); } //! In-place version of get_xyYtoRGB(). CImg& xyYtoRGB() { return xyYtoXYZ().XYZtoRGB(); } //! Convert a (R,G,B) image to a (H,S,V) one. CImg get_RGBtoHSV() const { return (+*this).RGBtoHSV(); } //! Convert a (H,S,V) image to a (R,G,B) one. CImg get_HSVtoRGB() const { return (+*this).HSVtoRGB(); } //! Convert a (R,G,B) image to a (Y,Cb,Cr) one. CImg get_RGBtoYCbCr() const { return (+*this).RGBtoYCbCr(); } //! Convert a (Y,Cb,Cr) image to a (R,G,B) one. CImg get_YCbCrtoRGB() const { return (+*this).YCbCrtoRGB(); } //! Convert a (R,G,B) image into a (Y,U,V) one. CImg::type> get_RGBtoYUV() const { typedef typename cimg::largest::type restype; return CImg(*this,false).RGBtoYUV(); } //! Convert a (Y,U,V) image into a (R,G,B) one. CImg get_YUVtoRGB() const { return (+*this).YUVtoRGB(); } //! Convert a (R,G,B) image to a (X,Y,Z) one. CImg::type> get_RGBtoXYZ() const { typedef typename cimg::largest::type restype; return CImg(*this,false).RGBtoXYZ(); } //! Convert a (X,Y,Z) image to a (R,G,B) one. CImg get_XYZtoRGB() const { return (+*this).XYZtoRGB(); } //! Convert a (X,Y,Z) image to a (L,a,b) one. CImg get_XYZtoLab() const { return (+*this).XYZtoLab(); } //! Convert a (L,a,b) image to a (X,Y,Z) one. CImg get_LabtoXYZ() const { return (+*this).LabtoXYZ(); } //! Convert a (X,Y,Z) image to a (x,y,Y) one. CImg get_XYZtoxyY() const { return (+*this).XYZtoxyY(); } //! Convert a (x,y,Y) image to a (X,Y,Z) one. CImg get_xyYtoXYZ() const { return (+*this).xyYtoXYZ(); } //! Convert a (R,G,B) image to a (L,a,b) one. CImg get_RGBtoLab() const { return (+*this).RGBtoLab(); } //! Convert a (L,a,b) image to a (R,G,B) one. CImg get_LabtoRGB() const { return (+*this).LabtoRGB(); } //! Convert a (R,G,B) image to a (x,y,Y) one. CImg get_RGBtoxyY() const { return (+*this).RGBtoxyY(); } //! Convert a (x,y,Y) image to a (R,G,B) one. CImg get_xyYtoRGB() const { return (+*this).xyYtoRGB(); } //@} //------------------- // //! \name Drawing //@{ //------------------- // Should be used only by member functions. Not an user-friendly function. // Pre-requisites : x0=0) { if (opacity>=1) { int off = whz-dx-1; if (sizeof(T)!=1) cimg_forV(*this,k) { const T val = (T)(*(col++)*brightness); for (int x=dx; x>=0; x--) *(ptrd++)=val; ptrd+=off; } else cimg_forV(*this,k) { std::memset(ptrd,(int)(*(col++)*brightness),dx+1); ptrd+=whz; } col-=dim; } else { int off = whz-dx-1; cimg_forV(*this,k) { const T val = (T)(*(col++)*brightness); for (int x=dx; x>=0; x--) { *ptrd = (T)(val*nopacity + *ptrd*copacity); ptrd++; } ptrd+=off; } col-=dim; } } } return *this; } CImg& draw_scanline(const T *const color,const float opacity=1) { return draw_scanline(0,0,0,color,opacity,1.0f,true); } //! Draw a colored point in the instance image, at coordinates (\c x0,\c y0,\c z0). /** \param x0 = X-coordinate of the vector-valued pixel to plot. \param y0 = Y-coordinate of the vector-valued pixel to plot. \param z0 = Z-coordinate of the vector-valued pixel to plot. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_point(const int x0, const int y0, const int z0, const T *const color,const float opacity=1) { if (!is_empty()) { if (!color) throw CImgArgumentException("CImg<%s>::draw_point() : Specified color is (null)",pixel_type()); if (x0>=0 && y0>=0 && z0>=0 && x0=1) cimg_forV(*this,k) { *ptrd = *(col++); ptrd+=whz; } else cimg_forV(*this,k) { *ptrd=(T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whz; } } } return *this; } //! Draw a colored point in the instance image, at coordinates (\c x0,\c y0). /** \param x0 = X-coordinate of the vector-valued pixel to plot. \param y0 = Y-coordinate of the vector-valued pixel to plot. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_point(const int x0, const int y0, const T *const color, const float opacity=1) { return draw_point(x0,y0,0,color,opacity); } //! Draw a 2D colored line in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). /** \param x0 = X-coordinate of the starting point of the line. \param y0 = Y-coordinate of the starting point of the line. \param x1 = X-coordinate of the ending point of the line. \param y1 = Y-coordinate of the ending point of the line. \param color = array of dimv() values of type \c T, defining the drawing color. \param pattern = An integer whose bits describes the line pattern. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_line(const int x0, const int y0, const int x1, const int y1, const T *const color, const unsigned int pattern=~0L, const float opacity=1) { if (!is_empty()) { if (!color) throw CImgArgumentException("CImg<%s>::draw_line() : Specified color is (null)",pixel_type()); const T* col=color; int nx0 = x0, nx1 = x1, ny0 = y0, ny1 = y1; if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1); if (nx1<0 || nx0>=dimx()) return *this; if (nx0<0) { ny0-=nx0*(ny1-ny0)/(nx1-nx0); nx0=0; } if (nx1>=dimx()) { ny1+=(nx1-dimx())*(ny0-ny1)/(nx1-nx0); nx1=dimx()-1;} if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); if (ny1<0 || ny0>=dimy()) return *this; if (ny0<0) { nx0-=ny0*(nx1-nx0)/(ny1-ny0); ny0=0; } if (ny1>=dimy()) { nx1+=(ny1-dimy())*(nx0-nx1)/(ny1-ny0); ny1=dimy()-1;} const bool steep = (ny1-ny0)>cimg::abs(nx1-nx0); if (steep) cimg::swap(nx0,ny0,nx1,ny1); if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1); const int dx = nx1-nx0, dy = cimg::abs(ny1-ny0), offx = steep?width:1, offy = (ny0=1) cimg_forV(*this,k) { unsigned int hatch=1; T *ptrd = steep?ptr(ny0,nx0,0,k):ptr(nx0,ny0,0,k); const T c = *(col++); for (int error=0, x=nx0; x<=nx1; x++) { if (!(~pattern) || (~pattern && pattern&hatch)) *ptrd=c; ptrd+=offx; if (((error+=dy)<<1)>=dx) { ptrd+=offy; error-=dx; } if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); } } else { const float nopacity = cimg::abs(opacity), copacity=1-cimg::max(opacity,0.0f); cimg_forV(*this,k) { unsigned int hatch=1; T *ptrd = steep?ptr(ny0,nx0,0,k):ptr(nx0,ny0,0,k); const T c = *(col++); for (int error=0, x=nx0; x<=nx1; x++) { if (!(~pattern) || (~pattern && pattern&hatch)) *ptrd = (T)(c*nopacity + copacity*(*ptrd)); ptrd+=offx; if (((error+=dy)<<1)>=dx) { ptrd+=offy; error-=dx; } if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); } } } } return *this; } //! Draw a 2D colored line in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). /** \param x0 = X-coordinate of the starting point of the line. \param y0 = Y-coordinate of the starting point of the line. \param x1 = X-coordinate of the ending point of the line. \param y1 = Y-coordinate of the ending point of the line. \param color = array of dimv() values of type \c T, defining the drawing color. \param pattern = An integer whose bits describes the line pattern. \param opacity = opacity of the drawing. \note Clipping is supported. **/ template CImg& draw_line(const CImg& coords, const T *const color, const unsigned int pattern=~0L, const float opacity=1) { if (!is_empty() && coords) { if (coords.height==1) throw CImgArgumentException("CImg<%s>::draw_line() : Incorrect coordinates (%u,%u,%u,%u,%p).", pixel_type(),coords.width,coords.height,coords.depth,coords.dim,coords.data); int ox = (int)coords(0,0), oy = (int)coords(0,1); if (coords.height==2) for (unsigned int i=1; i::draw_line() : Specified color is (null)",pixel_type()); const T* col=color; unsigned int hatch=1; int nx0 = x0, ny0 = y0, nz0 = z0, nx1 = x1, ny1 = y1, nz1 = z1; if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (nx1<0 || nx0>=dimx()) return *this; if (nx0<0) { const int D=1+nx1-nx0; ny0-=nx0*(1+ny1-ny0)/D; nz0-=nx0*(1+nz1-nz0)/D; nx0=0; } 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;} if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (ny1<0 || ny0>=dimy()) return *this; if (ny0<0) { const int D=1+ny1-ny0; nx0-=ny0*(1+nx1-nx0)/D; nz0-=ny0*(1+nz1-nz0)/D; ny0=0; } 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;} if (nz0>nz1) cimg::swap(nx0,nx1,ny0,ny1,nz0,nz1); if (nz1<0 || nz0>=dimz()) return *this; if (nz0<0) { const int D=1+nz1-nz0; nx0-=nz0*(1+nx1-nx0)/D; ny0-=nz0*(1+ny1-ny0)/D; nz0=0; } 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;} const unsigned int dmax = cimg::max(cimg::abs(nx1-nx0),cimg::abs(ny1-ny0),nz1-nz0), whz = width*height*depth; const float px = (nx1-nx0)/(float)dmax, py = (ny1-ny0)/(float)dmax, pz = (nz1-nz0)/(float)dmax; float x = (float)nx0, y = (float)ny0, z = (float)nz0; if (opacity>=1) for (unsigned int t=0; t<=dmax; t++) { if (!(~pattern) || (~pattern && pattern&hatch)) { T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0); cimg_forV(*this,k) { *ptrd=*(col++); ptrd+=whz; } col-=dim; } x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); } else { const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); for (unsigned int t=0; t<=dmax; t++) { if (!(~pattern) || (~pattern && pattern&hatch)) { T* ptrd = ptr((unsigned int)x,(unsigned int)y,(unsigned int)z,0); cimg_forV(*this,k) { *ptrd = (T)(*(col++)*nopacity + copacity*(*ptrd)); ptrd+=whz; } col-=dim; } x+=px; y+=py; z+=pz; if (pattern) hatch=(hatch<<1)+(hatch>>(sizeof(unsigned int)*8-1)); } } } return *this; } //! Draw a 2D textured line in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). /** \param x0 = X-coordinate of the starting point of the line. \param y0 = Y-coordinate of the starting point of the line. \param x1 = X-coordinate of the ending point of the line. \param y1 = Y-coordinate of the ending point of the line. \param texture = a colored texture image used to draw the line color. \param tx0 = X-coordinate of the starting point of the texture. \param ty0 = Y-coordinate of the starting point of the texture. \param tx1 = X-coordinate of the ending point of the texture. \param ty1 = Y-coordinate of the ending point of the texture. \param opacity = opacity of the drawing. \note Clipping is supported, but texture coordinates do not support clipping. **/ template CImg& draw_line(const int x0,const int y0,const int x1,const int y1, const CImg& texture, const int tx0,const int ty0,const int tx1,const int ty1, const float opacity=1) { if (!is_empty()) { if (!texture || texture.dim::draw_line() : specified texture (%u,%u,%u,%u,%p) has wrong dimensions.", pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); int nx0=x0, ny0=y0, nx1=x1, ny1=y1, ntx0=tx0, nty0=ty0, ntx1=tx1, nty1=ty1; if (nx0>nx1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); if (nx1<0 || nx0>=dimx()) return *this; if (nx0<0) { const int D=nx1-nx0; ny0-=nx0*(ny1-ny0)/D; ntx0-=nx0*(ntx1-ntx0)/D; nty0-=nx0*(nty1-nty0)/D; nx0=0; } if (nx1>=dimx()) { const int d=nx1-dimx(),D=nx1-nx0; ny1+=d*(ny0-ny1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; nx1=dimx()-1; } if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); if (ny1<0 || ny0>=dimy()) return *this; if (ny0<0) { const int D=ny1-ny0; nx0-=ny0*(nx1-nx0)/D; ntx0-=ny0*(ntx1-ntx0)/D; nty0-=ny0*(nty1-nty0)/D; ny0=0; } if (ny1>=dimy()) { const int d=ny1-dimy(),D=ny1-ny0; nx1+=d*(nx0-nx1)/D; ntx1+=d*(ntx0-ntx1)/D; nty1+=d*(nty0-nty1)/D; ny1=dimy()-1; } const unsigned int dmax = (unsigned int)cimg::max(cimg::abs(nx1-nx0),ny1-ny0), whz = width*height*depth, twhz = texture.width*texture.height*texture.depth; const float px = dmax?(nx1-nx0)/(float)dmax:0, py = dmax?(ny1-ny0)/(float)dmax:0, tpx = dmax?(ntx1-ntx0)/(float)dmax:0, tpy = dmax?(nty1-nty0)/(float)dmax:0; float x = (float)nx0, y = (float)ny0, tx = (float)ntx0, ty = (float)nty0; if (opacity>=1) for (unsigned int tt=0; tt<=dmax; tt++) { T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); const t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0); cimg_forV(*this,k) { *ptrd = (T)*ptrs; ptrd+=whz; ptrs+=twhz; } x+=px; y+=py; tx+=tpx; ty+=tpy; } else { const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); for (unsigned int tt=0; tt<=dmax; tt++) { T *ptrd = ptr((unsigned int)x,(unsigned int)y,0,0); const t *ptrs = texture.ptr((unsigned int)tx,(unsigned int)ty,0,0); cimg_forV(*this,k) { *ptrd = (T)(nopacity*(*ptrs) + copacity*(*ptrd)); ptrd+=whz; ptrs+=twhz; } x+=px; y+=py; tx+=tpx; ty+=tpy; } } } return *this; } //! Draw a 2D colored arrow in the instance image, at coordinates (\c x0,\c y0)->(\c x1,\c y1). /** \param x0 = X-coordinate of the starting point of the arrow (tail). \param y0 = Y-coordinate of the starting point of the arrow (tail). \param x1 = X-coordinate of the ending point of the arrow (head). \param y1 = Y-coordinate of the ending point of the arrow (head). \param color = array of dimv() values of type \c T, defining the drawing color. \param angle = aperture angle of the arrow head \param length = length of the arrow head. If <0, described as a percentage of the arrow length. \param pattern = An integer whose bits describes the line pattern. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_arrow(const int x0,const int y0,const int x1,const int y1, const T *const color, const float angle=30,const float length=-10,const unsigned int pattern=~0L,const float opacity=1) { if (!is_empty()) { const float u = (float)(x0-x1), v = (float)(y0-y1), sq = u*u+v*v, deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.0f, l = (length>=0)?length:-length*(float)std::sqrt(sq)/100; if (sq>0) { const double cl = std::cos(ang-deg), sl = std::sin(ang-deg), cr = std::cos(ang+deg), sr = std::sin(ang+deg); const int xl = x1+(int)(l*cl), yl = y1+(int)(l*sl), xr = x1+(int)(l*cr), yr = y1+(int)(l*sr), xc = x1+(int)((l+1)*(cl+cr))/2, yc = y1+(int)((l+1)*(sl+sr))/2; draw_line(x0,y0,xc,yc,color,pattern,opacity).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); } else draw_point(x0,y0,color,opacity); } return *this; } //! Draw a sprite image in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0). /** \param sprite = sprite image. \param x0 = X-coordinate of the sprite position in the instance image. \param y0 = Y-coordinate of the sprite position in the instance image. \param z0 = Z-coordinate of the sprite position in the instance image. \param v0 = V-coordinate of the sprite position in the instance image. \param opacity = opacity of the drawing. \note Clipping is supported. **/ template CImg& draw_image(const CImg& sprite, const int x0=0, const int y0=0, const int z0=0, const int v0=0, const float opacity=1) { if (!is_empty()) { if (!sprite) throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); const int lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); const t *ptrs = sprite.ptr() - (bx?x0:0) - (by?y0*sprite.dimx():0) - (bz?z0*sprite.dimx()*sprite.dimy():0) - (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0); const unsigned int offX = width-lX, soffX = sprite.width-lX, offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ); const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); if (lX>0 && lY>0 && lZ>0 && lV>0) for (int v=0; v=1) for (int x=0; x::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); if (this==&sprite) return draw_image(CImg(sprite),x0,y0,z0,v0,opacity); const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); const int lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); const T *ptrs = sprite.ptr() - (bx?x0:0) - (by?y0*sprite.dimx():0) - (bz?z0*sprite.dimx()*sprite.dimy():0) - (bv?v0*sprite.dimx()*sprite.dimy()*sprite.dimz():0); const unsigned int offX = width-lX, soffX = sprite.width-lX, offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ), slX = lX*sizeof(T); const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); if (lX>0 && lY>0 && lZ>0 && lV>0) for (int v=0; v=1) for (int y=0; y CImg& draw_image(const CImg& sprite, const CImg& mask, const int x0=0, const int y0=0, const int z0=0, const int v0=0, const tm mask_valmax='\1', const float opacity=1) { if (!is_empty()) { if (!sprite) throw CImgArgumentException("CImg<%s>::draw_image() : Specified sprite image (%u,%u,%u,%u,%p) is empty.", pixel_type(),sprite.width,sprite.height,sprite.depth,sprite.dim,sprite.data); if (!mask) throw CImgArgumentException("CImg<%s>::draw_image() : Specified mask image (%u,%u,%u,%u,%p) is empty.", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); if ((void*)this==(void*)&sprite) return draw_image(CImg(sprite),mask,x0,y0,z0,v0); if(mask.width!=sprite.width || mask.height!=sprite.height || mask.depth!=sprite.depth) throw CImgArgumentException("CImg<%s>::draw_image() : Mask dimension is (%u,%u,%u,%u), while sprite is (%u,%u,%u,%u)", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,sprite.width,sprite.height,sprite.depth,sprite.dim); const bool bx=(x0<0), by=(y0<0), bz=(z0<0), bv=(v0<0); const int lX = sprite.dimx() - (x0+sprite.dimx()>dimx()?x0+sprite.dimx()-dimx():0) + (bx?x0:0), lY = sprite.dimy() - (y0+sprite.dimy()>dimy()?y0+sprite.dimy()-dimy():0) + (by?y0:0), lZ = sprite.dimz() - (z0+sprite.dimz()>dimz()?z0+sprite.dimz()-dimz():0) + (bz?z0:0), lV = sprite.dimv() - (v0+sprite.dimv()>dimv()?v0+sprite.dimv()-dimv():0) + (bv?v0:0); const int 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), ssize = mask.dimx()*mask.dimy()*mask.dimz(); const ti *ptrs = sprite.ptr() + coff; const tm *ptrm = mask.ptr() + coff; const unsigned int offX = width-lX, soffX = sprite.width-lX, offY = width*(height-lY), soffY = sprite.width*(sprite.height-lY), offZ = width*height*(depth-lZ), soffZ = sprite.width*sprite.height*(sprite.depth-lZ); T *ptrd = ptr(x0<0?0:x0,y0<0?0:y0,z0<0?0:z0,v0<0?0:v0); if (lX>0 && lY>0 && lZ>0 && lV>0) for (int v=0; v=dimx()?dimx()-1-nx1:0) + (nx0<0?nx0:0), lY = (1+ny1-ny0) + (ny1>=dimy()?dimy()-1-ny1:0) + (ny0<0?ny0:0), lZ = (1+nz1-nz0) + (nz1>=dimz()?dimz()-1-nz1:0) + (nz0<0?nz0:0), lV = (1+nv1-nv0) + (nv1>=dimv()?dimv()-1-nv1:0) + (nv0<0?nv0:0); const unsigned int offX = width-lX, offY = width*(height-lY), offZ = width*height*(depth-lZ); const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); T *ptrd = ptr(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nv0<0?0:nv0); if (lX>0 && lY>0 && lZ>0 && lV>0) for (int v=0; v=1) { if (sizeof(T)!=1) { for (int x=0; x::draw_rectangle : specified color is (null)",pixel_type()); cimg_forV(*this,k) draw_rectangle(x0,y0,z0,k,x1,y1,z1,k,color[k],opacity); return *this; } //! Draw a 2D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1). /** \param x0 = X-coordinate of the upper-left rectangle corner in the instance image. \param y0 = Y-coordinate of the upper-left rectangle corner in the instance image. \param x1 = X-coordinate of the lower-right rectangle corner in the instance image. \param y1 = Y-coordinate of the lower-right rectangle corner in the instance image. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_rectangle(const int x0,const int y0,const int x1,const int y1, const T *const color,const float opacity=1) { draw_rectangle(x0,y0,0,x1,y1,depth-1,color,opacity); return *this; } //! Draw a 2D filled colored triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing (<1) \param brightness = brightness of the drawing (in [0,1]) \note Clipping is supported. **/ CImg& draw_triangle(const int x0,const int y0, const int x1,const int y1, const int x2,const int y2, const T *const color, const float opacity=1, const float brightness=1) { draw_scanline(color,opacity); int nx0 = x0, ny0 = y0, nx1 = x1, ny1 = y1, nx2 = x2, ny2 = y2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1); float xleft = (float)nx0, xright = xleft, pleft = (p1dimy()?height:ny1; for (int y=ny0<0?0:ny0; y=dimy()?height-1:ny2; for (int yy=ny1<0?0:ny1; yy<=yb; yy++) { draw_scanline((int)xleft,(int)xright,yy,color,opacity,brightness); xleft+=pleft; xright+=pright; } return *this; } //! Draw a 2D Gouraud-filled triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param color = array of dimv() values of type \c T, defining the global drawing color. \param c0 = brightness of the first corner. \param c1 = brightness of the second corner. \param c2 = brightness of the third corner. \param opacity = opacity of the drawing. \note Clipping is supported. **/ CImg& draw_triangle(const int x0, const int y0, const int x1, const int y1, const int x2, const int y2, const T *const color, const float c0, const float c1, const float c2, const float opacity=1) { if (!is_empty()) { int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,whz=width*height*depth; float nc0=c0,nc1=c1,nc2=c2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nc1,nc2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), cp1 = (ny1-ny0)?(nc1-nc0)/(float)(ny1-ny0):0, cp2 = (ny2-ny0)?(nc2-nc0)/(float)(ny2-ny0):0, cp3 = (ny2-ny1)?(nc2-nc1)/(float)(ny2-ny1):0; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); float pleft,pright,cpleft,cpright,xleft=(float)nx0,xright=xleft,cleft=nc0,cright=cleft; if (p1=0)?cleft:(cleft-xleft*cp); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { const T col = color[k]; float c=ci; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*col); c+=cp; } ptrd+=offx; } else cimg_forV(*this,k) { const T col = color[k]; float c=ci; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*col+copacity*(*ptrd)); ptrd++; c+=cp; } ptrd+=offx; } } xleft+=pleft; xright+=pright; cleft+=cpleft; cright+=cpright; } if (p1=dimy()?(height-1):ny2; for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { const int dx = (int)xright-(int)xleft; const float cp = dx?(cright-cleft)/dx:0, ci = (xleft>=0)?cleft:(cleft-xleft*cp); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { const T col = color[k]; float c=ci; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*col); c+=cp; } ptrd+=offx; } else cimg_forV(*this,k) { const T col = color[k]; float c=ci; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*col+copacity*(*ptrd)); ptrd++; c+=cp; } ptrd+=offx; } } xleft+=pleft; xright+=pright; cleft+=cpleft; cright+=cpright; } } return *this; } //! Draw a 2D phong-shaded triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param color = array of dimv() values of type \c T, defining the global drawing color. \param light = light image. \param lx0 = X-coordinate of the first corner in the light image. \param ly0 = Y-coordinate of the first corner in the light image. \param lx1 = X-coordinate of the second corner in the light image. \param ly1 = Y-coordinate of the second corner in the light image. \param lx2 = X-coordinate of the third corner in the light image. \param ly2 = Y-coordinate of the third corner in the light image. \param opacity = opacity of the drawing. \note Clipping is supported, but texture coordinates do not support clipping. **/ template CImg& draw_triangle(const int x0,const int y0, const int x1,const int y1, const int x2,const int y2, const T *const color, const CImg& light, const int lx0,const int ly0, const int lx1,const int ly1, const int lx2,const int ly2, const float opacity=1.0f) { if (!is_empty()) { if (!light) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light texture (%u,%u,%u,%u,%p) is empty.", pixel_type(),light.width,light.height,light.depth,light.dim,light.data); int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,nlx0=lx0,nly0=ly0,nlx1=lx1,nly1=ly1,nlx2=lx2,nly2=ly2,whz=width*height*depth; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,nlx0,nlx1,nly0,nly1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,nlx0,nlx2,nly0,nly2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,nlx1,nlx2,nly1,nly2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), lpx1 = (ny1-ny0)?(nlx1-nlx0)/(float)(ny1-ny0):0, lpy1 = (ny1-ny0)?(nly1-nly0)/(float)(ny1-ny0):0, lpx2 = (ny2-ny0)?(nlx2-nlx0)/(float)(ny2-ny0):0, lpy2 = (ny2-ny0)?(nly2-nly0)/(float)(ny2-ny0):0, lpx3 = (ny2-ny1)?(nlx2-nlx1)/(float)(ny2-ny1):0, lpy3 = (ny2-ny1)?(nly2-nly1)/(float)(ny2-ny1):0; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); float pleft,pright,lpxleft,lpyleft,lpxright,lpyright, xleft=(float)nx0,xright=xleft,lxleft=(float)nlx0,lyleft=(float)nly0,lxright=lxleft,lyright=lyleft; if (p1=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*color[k]); lx+=lpx; ly+=lpy; } ptrd+=offx; } else cimg_forV(*this,k) { float lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*color[k]+copacity*(*ptrd)); ptrd++; lx+=lpx; ly+=lpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; } if (p1=dimy()?(height-1):ny2; for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { const int dx = (int)xright-(int)xleft; const float lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*color[k]); lx+=lpx; ly+=lpy; } ptrd+=offx; } else cimg_forV(*this,k) { float lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*color[k]+copacity*(*ptrd)); ptrd++; lx+=lpx; ly+=lpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; } } return *this; } //! Draw a 2D textured triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param texture = texture image used to fill the triangle. \param tx0 = X-coordinate of the first corner in the texture image. \param ty0 = Y-coordinate of the first corner in the texture image. \param tx1 = X-coordinate of the second corner in the texture image. \param ty1 = Y-coordinate of the second corner in the texture image. \param tx2 = X-coordinate of the third corner in the texture image. \param ty2 = Y-coordinate of the third corner in the texture image. \param opacity = opacity of the drawing. \param brightness = brightness of the drawing. \note Clipping is supported, but texture coordinates do not support clipping. **/ template CImg& draw_triangle(const int x0,const int y0, const int x1,const int y1, const int x2,const int y2, const CImg& texture, const int tx0,const int ty0, const int tx1,const int ty1, const int tx2,const int ty2, const float opacity=1.0f, const float brightness=1.0f) { if (!is_empty()) { if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2,whz=width*height*depth; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); float pleft,pright,tpxleft,tpyleft,tpxright,tpyright, xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft; if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; } if (p1=dimy()?(height-1):ny2; for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { const int dx = (int)xright-(int)xleft; const float tpx = dx?((int)txright-(int)txleft)/(float)dx:0, tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*brightness*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; } } return *this; } //! Draw a 2D textured triangle with Gouraud-Shading in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param texture = texture image used to fill the triangle. \param tx0 = X-coordinate of the first corner in the texture image. \param ty0 = Y-coordinate of the first corner in the texture image. \param tx1 = X-coordinate of the second corner in the texture image. \param ty1 = Y-coordinate of the second corner in the texture image. \param tx2 = X-coordinate of the third corner in the texture image. \param ty2 = Y-coordinate of the third corner in the texture image. \param c0 = brightness value of the first corner. \param c1 = brightness value of the second corner. \param c2 = brightness value of the third corner. \param opacity = opacity of the drawing. \note Clipping is supported, but texture coordinates do not support clipping. **/ template CImg& draw_triangle(const int x0,const int y0, const int x1,const int y1, const int x2,const int y2, const CImg& texture, const int tx0,const int ty0, const int tx1,const int ty1, const int tx2,const int ty2, const float c0,const float c1,const float c2, const float opacity=1) { if (!is_empty()) { if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2,ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2,whz=width*height*depth; float nc0=c0,nc1=c1,nc2=c2; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nc0,nc1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nc0,nc2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nc1,nc2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0, cp1 = (ny1-ny0)?(nc1-nc0)/(float)(ny1-ny0):0, cp2 = (ny2-ny0)?(nc2-nc0)/(float)(ny2-ny0):0, cp3 = (ny2-ny1)?(nc2-nc1)/(float)(ny2-ny1):0; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,cpleft,cpright, xleft=(float)nx0,xright=xleft,txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft,cleft=nc0,cright=cleft; if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), ci = (xleft>=0)?cleft:(cleft-xleft*cp); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi, c=ci; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; c+=cp; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi, c=ci; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; c+=cp; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; cleft+=cpleft; cright+=cpright; } if (p1=dimy()?(height-1):ny2; for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { const int dx = (int)xright-(int)xleft; const float tpx = dx?((int)txright-(int)txleft)/(float)dx:0, tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, cp = dx?(cright-cleft)/dx:0, txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), ci = (xleft>=0)?cleft:(cleft-xleft*cp); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi, c=ci; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(c*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; c+=cp; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi, c=ci; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*c*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; c+=ci; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; cleft+=cpleft; cright+=cpright; } } return *this; } //! Draw a phong-shaded 2D textured triangle in the instance image, at coordinates (\c x0,\c y0)-(\c x1,\c y1)-(\c x2,\c y2). /** \param x0 = X-coordinate of the first corner in the instance image. \param y0 = Y-coordinate of the first corner in the instance image. \param x1 = X-coordinate of the second corner in the instance image. \param y1 = Y-coordinate of the second corner in the instance image. \param x2 = X-coordinate of the third corner in the instance image. \param y2 = Y-coordinate of the third corner in the instance image. \param texture = texture image used to fill the triangle. \param tx0 = X-coordinate of the first corner in the texture image. \param ty0 = Y-coordinate of the first corner in the texture image. \param tx1 = X-coordinate of the second corner in the texture image. \param ty1 = Y-coordinate of the second corner in the texture image. \param tx2 = X-coordinate of the third corner in the texture image. \param ty2 = Y-coordinate of the third corner in the texture image. \param light = light image. \param lx0 = X-coordinate of the first corner in the light image. \param ly0 = Y-coordinate of the first corner in the light image. \param lx1 = X-coordinate of the second corner in the light image. \param ly1 = Y-coordinate of the second corner in the light image. \param lx2 = X-coordinate of the third corner in the light image. \param ly2 = Y-coordinate of the third corner in the light image. \param opacity = opacity of the drawing. \note Clipping is supported, but texture coordinates do not support clipping. **/ template CImg& draw_triangle(const int x0,const int y0, const int x1,const int y1, const int x2,const int y2, const CImg& texture, const int tx0,const int ty0, const int tx1,const int ty1, const int tx2,const int ty2, const CImg& light, const int lx0,const int ly0, const int lx1,const int ly1, const int lx2,const int ly2, const float opacity=1.0f) { if (!is_empty()) { if (!texture) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified texture (%u,%u,%u,%u,%p) is empty.", pixel_type(),texture.width,texture.height,texture.depth,texture.dim,texture.data); if (!light) throw CImgArgumentException("CImg<%s>::draw_triangle() : Specified light (%u,%u,%u,%u,%p) is empty.", pixel_type(),light.width,light.height,light.depth,light.dim,light.data); int nx0=x0,ny0=y0,nx1=x1,ny1=y1,nx2=x2,ny2=y2, ntx0=tx0,nty0=ty0,ntx1=tx1,nty1=ty1,ntx2=tx2,nty2=ty2, nlx0=lx0,nly0=ly0,nlx1=lx1,nly1=ly1,nlx2=lx2,nly2=ly2, whz=width*height*depth; if (ny0>ny1) cimg::swap(nx0,nx1,ny0,ny1,ntx0,ntx1,nty0,nty1,nlx0,nlx1,nly0,nly1); if (ny0>ny2) cimg::swap(nx0,nx2,ny0,ny2,ntx0,ntx2,nty0,nty2,nlx0,nlx2,nly0,nly2); if (ny1>ny2) cimg::swap(nx1,nx2,ny1,ny2,ntx1,ntx2,nty1,nty2,nlx1,nlx2,nly1,nly2); if (ny0>=dimy() || ny2<0) return *this; const float p1 = (ny1-ny0)?(nx1-nx0)/(float)(ny1-ny0):(nx1-nx0), p2 = (ny2-ny0)?(nx2-nx0)/(float)(ny2-ny0):(nx2-nx0), p3 = (ny2-ny1)?(nx2-nx1)/(float)(ny2-ny1):(nx2-nx1), tpx1 = (ny1-ny0)?(ntx1-ntx0)/(float)(ny1-ny0):0, tpy1 = (ny1-ny0)?(nty1-nty0)/(float)(ny1-ny0):0, tpx2 = (ny2-ny0)?(ntx2-ntx0)/(float)(ny2-ny0):0, tpy2 = (ny2-ny0)?(nty2-nty0)/(float)(ny2-ny0):0, tpx3 = (ny2-ny1)?(ntx2-ntx1)/(float)(ny2-ny1):0, tpy3 = (ny2-ny1)?(nty2-nty1)/(float)(ny2-ny1):0, lpx1 = (ny1-ny0)?(nlx1-nlx0)/(float)(ny1-ny0):0, lpy1 = (ny1-ny0)?(nly1-nly0)/(float)(ny1-ny0):0, lpx2 = (ny2-ny0)?(nlx2-nlx0)/(float)(ny2-ny0):0, lpy2 = (ny2-ny0)?(nly2-nly0)/(float)(ny2-ny0):0, lpx3 = (ny2-ny1)?(nlx2-nlx1)/(float)(ny2-ny1):0, lpy3 = (ny2-ny1)?(nly2-nly1)/(float)(ny2-ny1):0; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); float pleft,pright,tpxleft,tpyleft,tpxright,tpyright,lpxleft,lpyleft,lpxright,lpyright, xleft=(float)nx0,xright=xleft, txleft=(float)ntx0,tyleft=(float)nty0,txright=txleft,tyright=tyleft, lxleft=(float)nlx0,lyleft=(float)nly0,lxright=lxleft,lyright=lyleft; if (p1=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi, lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi, lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; } if (p1=dimy()?(height-1):ny2; for (int yy=(ny1<0?0:ny1); yy<=yb; yy++) { const int dx = (int)xright-(int)xleft; const float tpx = dx?((int)txright-(int)txleft)/(float)dx:0, tpy = dx?((int)tyright-(int)tyleft)/(float)dx:0, txi = (float)((xleft>=0)?(int)txleft:(int)(txleft-(int)xleft*tpx)), tyi = (float)((xleft>=0)?(int)tyleft:(int)(tyleft-(int)xleft*tpy)), lpx = dx?((int)lxright-(int)lxleft)/(float)dx:0, lpy = dx?((int)lyright-(int)lyleft)/(float)dx:0, lxi = (float)((xleft>=0)?(int)lxleft:(int)(lxleft-(int)xleft*lpx)), lyi = (float)((xleft>=0)?(int)lyleft:(int)(lyleft-(int)xleft*lpy)); const int xmin=(xleft>=0)?(int)xleft:0, xmax=(xright=1) cimg_forV(*this,k) { float tx=txi, ty=tyi, lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *(ptrd++)=(T)(light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)); tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; } ptrd+=offx; } else cimg_forV(*this,k) { float tx=txi, ty=tyi, lx=lxi, ly=lyi; for (int x=xmin; x<=xmax; x++) { *ptrd=(T)(nopacity*light((unsigned int)lx,(unsigned int)ly)*texture((unsigned int)tx,(unsigned int)ty,0,k)+copacity*(*ptrd)); ptrd++; tx+=tpx; ty+=tpy; lx+=lpx; ly+=lpy; } ptrd+=offx; } } xleft+=pleft; xright+=pright; txleft+=tpxleft; tyleft+=tpyleft; txright+=tpxright; tyright+=tpyright; lxleft+=lpxleft; lyleft+=lpyleft; lxright+=lpxright; lyright+=lpyright; } } return *this; } //! Draw an ellipse on the instance image /** \param x0 = X-coordinate of the ellipse center. \param y0 = Y-coordinate of the ellipse center. \param r1 = First radius of the ellipse. \param r2 = Second radius of the ellipse. \param ru = X-coordinate of the orientation vector related to the first radius. \param rv = Y-coordinate of the orientation vector related to the first radius. \param color = array of dimv() values of type \c T, defining the drawing color. \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. \param opacity = opacity of the drawing. **/ CImg& draw_ellipse(const int x0,const int y0,const float r1,const float r2,const float ru,const float rv, const T *const color,const unsigned int pattern=0L, const float opacity=1) { if (!is_empty()) { draw_scanline(color,opacity); if (!color) throw CImgArgumentException("CImg<%s>::draw_ellipse : Specified color is (null).",pixel_type()); unsigned int hatch=1; const float nr1 = cimg::abs(r1), nr2 = cimg::abs(r2), norm = (float)std::sqrt(ru*ru+rv*rv), u = norm>0?ru/norm:1, v = norm>0?rv/norm:0, rmax = cimg::max(nr1,nr2), l1 = (float)std::pow(rmax/(nr1>0?nr1:1e-6),2), l2 = (float)std::pow(rmax/(nr2>0?nr2:1e-6),2), a = l1*u*u + l2*v*v, b = u*v*(l1-l2), c = l1*v*v + l2*u*u; const int yb = (int)std::sqrt(a*rmax*rmax/(a*c-b*b)), ymin = (y0-yb<0)?0:(y0-yb), ymax = (1+y0+yb>=dimy())?height-1:(1+y0+yb); int oxmin=0, oxmax=0; bool first_line = true; for (int y=ymin; y0?std::sqrt(delta):0)), fxmin = x0-(b*Y+sdelta)/a, fxmax = x0-(b*Y-sdelta)/a; const int xmin = (int)fxmin, xmax = (int)fxmax; if (!pattern) draw_scanline(xmin,xmax,y,color,opacity); else { if (!(~pattern) || (~pattern && pattern&hatch)) { if (first_line) { draw_scanline(xmin,xmax,y,color,opacity); first_line = false; } else { if (xmin>(sizeof(unsigned int)*8-1)); } } return *this; } //! Draw an ellipse on the instance image /** \param x0 = X-coordinate of the ellipse center. \param y0 = Y-coordinate of the ellipse center. \param tensor = Diffusion tensor describing the ellipse. \param color = array of dimv() values of type \c T, defining the drawing color. \param pattern = If zero, the ellipse is filled, else pattern is an integer whose bits describe the outline pattern. \param opacity = opacity of the drawing. **/ template CImg& draw_ellipse(const int x0,const int y0,const CImg &tensor, const T *color,const unsigned int pattern=0L,const float opacity=1) { CImgList eig = tensor.get_symmetric_eigen(); const CImg &val = eig[0], &vec = eig[1]; return draw_ellipse(x0,y0,val(0),val(1),vec(0,0),vec(0,1),color,pattern,opacity); } //! Draw a circle on the instance image /** \param x0 = X-coordinate of the circle center. \param y0 = Y-coordinate of the circle center. \param r = radius of the circle. \param color = an array of dimv() values of type \c T, defining the drawing color. \param pattern = If zero, the circle is filled, else pattern is an integer whose bits describe the outline pattern. \param opacity = opacity of the drawing. **/ CImg& draw_circle(const int x0,const int y0,float r,const T *const color,const unsigned int pattern=0L,const float opacity=1) { return draw_ellipse(x0,y0,r,r,1,0,color,pattern,opacity); } //! Draw a text into the instance image. /** \param text = a C-string containing the text to display. \param x0 = X-coordinate of the text in the instance image. \param y0 = Y-coordinate of the text in the instance image. \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent'). \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent'). \param font = List of font characters used for the drawing. \param opacity = opacity of the drawing. \note Clipping is supported. \see get_font(). **/ template CImg& draw_text(const char *const text, const int x0,const int y0, const T *const fgcolor,const T *const bgcolor, const CImgList& font,const float opacity=1) { if (!text) throw CImgArgumentException("CImg<%s>::draw_text() : Specified input string is (null).",pixel_type()); if (!font) throw CImgArgumentException("CImg<%s>::draw_text() : Specified font (%u,%p) is empty.", pixel_type(),font.size,font.data); if (is_empty()) { // If needed, pre-compute needed size of the image int x=0, y=0, w=0; for (int i=0; iw) w=x; x=0; break; case '\t': x+=4*font[' '].width; break; default: if (cw) w=x; y+=font[' '].height; } assign(x0+w,y0+y,1,font[' '].dim,0); if (bgcolor) cimg_forV(*this,k) get_shared_channel(k).fill(bgcolor[k]); } int x = x0, y = y0; CImg letter; for (int i=0; i=512) draw_image(letter,mask,x,y,0,0,(T)1,opacity); else draw_image(letter,x,y,0,0,opacity); x+=letter.width; } break; } } return *this; } //! Draw a text into the instance image. /** \param text = a C-string containing the text to display. \param x0 = X-coordinate of the text in the instance image. \param y0 = Y-coordinate of the text in the instance image. \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent'). \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent'). \param font_size = Height of the desired font (11,13,24,38 or 57) \param opacity = opacity of the drawing. \note Clipping is supported. \see get_font(). **/ CImg& draw_text(const char *const text, const int x0,const int y0, const T *const fgcolor,const T *const bgcolor=0, const unsigned int font_size=11,const float opacity=1.0f) { return draw_text(text,x0,y0,fgcolor,bgcolor,CImgList::get_font(font_size),opacity); } //! Draw a text into the instance image. /** \param x0 = X-coordinate of the text in the instance image. \param y0 = Y-coordinate of the text in the instance image. \param fgcolor = an array of dimv() values of type \c T, defining the foreground color (0 means 'transparent'). \param bgcolor = an array of dimv() values of type \c T, defining the background color (0 means 'transparent'). \param opacity = opacity of the drawing. \param format = a 'printf'-style format, followed by arguments. \note Clipping is supported. **/ CImg& draw_text(const int x0, const int y0, const T *const fgcolor, const T *const bgcolor, const unsigned int font_size, const float opacity, const char *format,...) { char tmp[2048]={0}; std::va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap); return draw_text(tmp,x0,y0,fgcolor,bgcolor,font_size,opacity); } template CImg& draw_text(const int x0,const int y0, const T *const fgcolor,const T *const bgcolor, const CImgList& font, const float opacity, const char *format,...) { char tmp[2048]={0}; std::va_list ap; va_start(ap,format); std::vsprintf(tmp,format,ap); va_end(ap); return draw_text(tmp,x0,y0,fgcolor,bgcolor,font,opacity); } //! Draw a vector field in the instance image. /** \param flow = a 2d image of 2d vectors used as input data. \param color = an array of dimv() values of type \c T, defining the drawing color. \param sampling = length (in pixels) between each arrow. \param factor = length factor of each arrow (if <0, computed as a percentage of the maximum length). \param quiver_type = type of plot. Can be 0 (arrows) or 1 (segments). \param opacity = opacity of the drawing. \note Clipping is supported. **/ template CImg& draw_quiver(const CImg& flow, const T *const color, const unsigned int sampling=25, const float factor=-20, const int quiver_type=0, const float opacity=1) { if (!is_empty()) { if (!flow || flow.dim<2) throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.", pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data); if (!color) throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color is (null)", pixel_type()); if (sampling<=0) throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g", pixel_type(),sampling); float vmax,fact; if (factor<=0) { const CImgStats st(flow.get_norm_pointwise(2),false); const float vmaxtmp = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max)); vmax = vmaxtmp>0?vmaxtmp:1; fact = -factor; } else { fact = factor; vmax = 1; } for (unsigned int y=sampling/2; y CImg& draw_quiver(const CImg& flow, const CImg& color, const unsigned int sampling=25, const float factor=-20, const int quiver_type=0, const float opacity=1) { if (!is_empty()) { if (!flow || flow.dim!=2) throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified flow (%u,%u,%u,%u,%p) has wrong dimensions.", pixel_type(),flow.width,flow.height,flow.depth,flow.dim,flow.data); if (!color || color.width!=flow.width || color.height!=flow.height) throw CImgArgumentException("CImg<%s>::draw_quiver() : Specified color (%u,%u,%u,%u,%p) has wrong dimensions.", pixel_type(),color.width,color.height,color.depth,color.dim,color.data); if (sampling<=0) throw CImgArgumentException("CImg<%s>::draw_quiver() : Incorrect sampling value = %g",pixel_type(),sampling); float vmax,fact; if (factor<=0) { const CImgStats st(flow.get_norm_pointwise(2),false); vmax = (float)cimg::max(cimg::abs(st.min),cimg::abs(st.max)); fact = -factor; } else { fact = factor; vmax = 1; } for (unsigned int y=sampling/2; y CImg& draw_graph(const CImg& data, const T *const color, const unsigned int gtype=0, const double ymin=0, const double ymax=0, const float opacity=1) { if (!is_empty()) { if (!color) throw CImgArgumentException("CImg<%s>::draw_graph() : Specified color is (null)",pixel_type()); T *color1 = new T[dim], *color2 = new T[dim]; cimg_forV(*this,k) { color1[k]=(T)(color[k]*0.6f); color2[k]=(T)(color[k]*0.3f); } CImgStats st; if (ymin==ymax) { st = CImgStats(data,false); cimg::swap(st.min,st.max); } else { st.min = ymin; st.max = ymax; } if (st.min==st.max) { st.min--; st.max++; } const float ca = height>1?(float)(st.max-st.min)/(height-1):0, cb = (float)st.min; const int Y0 = (int)(-cb/ca); int pY=0; cimg_foroff(data,off) { const int Y = (int)((data[off]-cb)/ca); switch (gtype) { case 0: // plot with segments if (off>0) draw_line((int)((off-1)*width/data.size()),pY,(int)(off*width/data.size()),Y,color,~0L,opacity); break; case 1: { // plot with bars const unsigned int X = off*width/data.size(), nX = (off+1)*width/data.size()-1; draw_rectangle(X,(int)Y0,nX,Y,color1,opacity); draw_line(X,Y,X,(int)Y0,color2,~0L,opacity); draw_line(X,(int)Y0,nX,(int)Y0,Y<=Y0?color2:color,~0L,opacity); draw_line(nX,Y,nX,(int)Y0,color,~0L,opacity); draw_line(X,Y,nX,Y,Y<=Y0?color:color2,~0L,opacity); } break; } pY=Y; } if (gtype==2) { // plot with cubic interpolation const CImg ndata = data.get_shared_points(0,data.size()-1); cimg_forX(*this,x) { const int Y = (int)((ndata.cubic_pix1d((float)x*ndata.width/width)-cb)/ca); if (x>0) draw_line(x,pY,x+1,Y,color,~0L,opacity); pY=Y; } } delete[] color1; delete[] color2; } return *this; } //! Draw a labeled horizontal axis on the instance image. /** \param x0 = lower bound of the x-range. \param x1 = upper bound of the x-range. \param y = Y-coordinate of the horizontal axis in the instance image. \param color = an array of dimv() values of type \c T, defining the drawing color. \param precision = precision of the labels. \param grid_pattern = pattern of the grid \param opacity = opacity of the drawing. \note if \c precision==0, precision of the labels is automatically computed. \see draw_graph(). **/ template CImg& draw_axis(const CImg& xvalues, const int y, const T *const color, const float opacity=1.0f) { if (!is_empty()) { int siz = (int)xvalues.size()-1; if (siz<=0) draw_line(0,y,width-1,y,color,~0L,opacity); else { if (xvalues[0] CImg& draw_axis(const int x, const CImg& yvalues, const T *const color, const float opacity=1.0f) { if (!is_empty()) { int siz = (int)yvalues.size()-1; if (siz<=0) draw_line(x,0,x,height-1,color,~0L,opacity); else { if (yvalues[0]=(int)height-11?(int)height-11:tmp), xt = x-(int)std::strlen(txt)*7; draw_point(x-1,yi,color,opacity).draw_point(x+1,yi,color,opacity); if (xt>0) draw_text(txt,xt,nyi,color,0,11,opacity); else draw_text(txt,x+3,nyi,color,0,11,opacity); } } } return *this; } //! Draw a labeled horizontal+vertical axis on the instance image. template CImg& draw_axis(const CImg& xvalues, const CImg& yvalues, const T *const color, const float opacity=1.0f) { if (!is_empty()) { const CImg nxvalues(xvalues.data,xvalues.size(),1,1,1,true); const int sizx = (int)xvalues.size()-1, wm1 = (int)(width)-1; if (sizx>0) { float ox = (float)nxvalues[0]; for (unsigned int x=1; x nyvalues(yvalues.data,yvalues.size(),1,1,1,true); const int sizy = (int)yvalues.size()-1, hm1 = (int)(height)-1; if (sizy>0) { float oy = (float)nyvalues[0]; for (unsigned int y=1; y::sequence(subdivisionx>0?subdivisionx:1-(int)width/subdivisionx,x0,x1).round(px), CImg::sequence(subdivisiony>0?subdivisiony:1-(int)height/subdivisiony,y0,y1).round(py), color,opacity); } //! Draw grid on the instance image template CImg& draw_grid(const CImg& xvalues, const CImg& yvalues, const T *const color, const unsigned int patternx=~0U, const unsigned int patterny=~0U, const float opacity=1.0f) { if (!is_empty()) { if (xvalues) cimg_foroff(xvalues,x) { const int xi = (int)xvalues[x]; if (xi>=0 && xi<(int)width) draw_line(xi,0,xi,height-1,color,patternx,opacity); } if (yvalues) cimg_foroff(yvalues,y) { const int yi = (int)yvalues[y]; if (yi>=0 && yi<(int)height) draw_line(0,yi,width-1,yi,color,patterny,opacity); } } return *this; } //! Draw grid on the instance image CImg& draw_grid(const float deltax, const float deltay, const float offsetx, const float offsety, const T *const color, const unsigned int patternx=~0U, const unsigned int patterny=~0U, const bool invertx=false, const bool inverty=false, const float opacity=1.0f) { CImg seqx, seqy; if (deltax!=0) { const float dx = deltax>0?deltax:width*-deltax/100; const unsigned int nx = (unsigned int)(width/dx); seqx = CImg::sequence(1+nx,0,(unsigned int)(dx*nx)); if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x)+offsetx,(float)width); if (invertx) cimg_foroff(seqx,x) seqx(x) = width-1-seqx(x); } if (deltay!=0) { const float dy = deltay>0?deltay:height*-deltay/100; const unsigned int ny = (unsigned int)(height/dy); seqy = CImg::sequence(1+ny,0,(unsigned int)(dy*ny)); if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y)+offsety,(float)height); if (inverty) cimg_foroff(seqy,y) seqy(y) = height-1-seqy(y); } return draw_grid(seqx,seqy,color,patternx,patterny,opacity); } // INNER CLASS used by function CImg<>::draw_fill() template struct _draw_fill { const T1 *const color; const float sigma,opacity; const CImg value; CImg region; _draw_fill(const CImg& img,const int x,const int y,const int z, const T *const pcolor,const float psigma,const float popacity): color(pcolor),sigma(psigma),opacity(popacity), value(img.get_vector_at(x,y,z)), region(CImg(img.width,img.height,img.depth,1,(T2)false)) { } _draw_fill& operator=(const _draw_fill& d) { color = d.color; sigma = d.sigma; opacity = d.opacity; value = d.value; region = d.region; return *this; } bool comp(const CImg& A,const CImg& B) const { bool res=true; const T *pA=A.data+A.size(); for (const T *pB=B.data+B.size(); res && pA>A.data; res=(cimg::abs(*(--pA)-(*(--pB)))<=sigma) ); return res; } void fill(CImg& img,const int x,const int y,const int z) { if (x<0 || x>=img.dimx() || y<0 || y>=img.dimy() || z<0 || z>=img.dimz()) return; if (!region(x,y,z) && comp(value,img.get_vector_at(x,y,z))) { const T *col=color; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); int xmin,xmax; if (opacity>=1) cimg_forV(img,k) img(x,y,z,k)=*(col++); else cimg_forV(img,k) img(x,y,z,k)=(T1)(*(col++)*opacity+copacity*img(x,y,z,k)); col-=img.dim; region(x,y,z) = (T2)true; for (xmin=x-1; xmin>=0 && comp(value,img.get_vector_at(xmin,y,z)); xmin--) { if (opacity>=1) cimg_forV(img,k) img(xmin,y,z,k) = *(col++); else cimg_forV(img,k) img(xmin,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmin,y,z,k)); col-=img.dim; region(xmin,y,z)=(T2)true; } for (xmax=x+1; xmax=1) cimg_forV(img,k) img(xmax,y,z,k) = *(col++); else cimg_forV(img,k) img(xmax,y,z,k)=(T1)(*(col++)*nopacity+copacity*img(xmax,y,z,k)); col-=img.dim; region(xmax,y,z)=(T2)true; } xmin++; xmax--; for (; xmin<=xmax; xmin++) { fill(img,xmin,y-1,z); fill(img,xmin,y+1,z); fill(img,xmin,y,z-1); fill(img,xmin,y,z+1); } } } }; //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image. /** \param x = X-coordinate of the starting point of the region to fill. \param y = Y-coordinate of the starting point of the region to fill. \param z = Z-coordinate of the starting point of the region to fill. \param color = an array of dimv() values of type \c T, defining the drawing color. \param region = image that will contain the mask of the filled region mask, as an output. \param sigma = tolerance concerning neighborhood values. \param opacity = opacity of the drawing. \return \p region is initialized with the binary mask of the filled region. **/ template CImg& draw_fill(const int x,const int y,const int z, const T *const color, CImg& region,const float sigma=0, const float opacity=1) { _draw_fill F(*this,x,y,z,color,sigma,opacity); F.fill(*this,x,y,z); region = F.region; return *this; } //! Draw a 3D filled region starting from a point (\c x,\c y,\ z) in the instance image. /** \param x = X-coordinate of the starting point of the region to fill. \param y = Y-coordinate of the starting point of the region to fill. \param z = Z-coordinate of the starting point of the region to fill. \param color = an array of dimv() values of type \c T, defining the drawing color. \param sigma = tolerance concerning neighborhood values. \param opacity = opacity of the drawing. **/ CImg& draw_fill(const int x,const int y,const int z,const T *const color,const float sigma=0,const float opacity=1) { CImg tmp; return draw_fill(x,y,z,color,tmp,sigma,opacity); } //! Draw a 2D filled region starting from a point (\c x,\c y) in the instance image. /** \param x = X-coordinate of the starting point of the region to fill. \param y = Y-coordinate of the starting point of the region to fill. \param color = an array of dimv() values of type \c T, defining the drawing color. \param sigma = tolerance concerning neighborhood values. \param opacity = opacity of the drawing. **/ CImg& draw_fill(const int x,const int y,const T *const color,const float sigma=0,const float opacity=1) { CImg tmp; return draw_fill(x,y,0,color,tmp,sigma,opacity); } //! Draw a plasma square in the instance image. /** \param x0 = X-coordinate of the upper-left corner of the plasma. \param y0 = Y-coordinate of the upper-left corner of the plasma. \param x1 = X-coordinate of the lower-right corner of the plasma. \param y1 = Y-coordinate of the lower-right corner of the plasma. \param alpha = Alpha-parameter of the plasma. \param beta = Beta-parameter of the plasma. \param opacity = opacity of the drawing. **/ CImg& draw_plasma(const int x0, const int y0, const int x1, const int y1, const double alpha=1.0, const double beta=1.0, const float opacity=1) { if (!is_empty()) { int nx0=x0,nx1=x1,ny0=y0,ny1=y1; if (nx1=dimx()) nx1=width-1; if (ny0<0) ny0=0; if (ny1>=dimy()) ny1=height-1; const int xc = (nx0+nx1)/2, yc = (ny0+ny1)/2, dx=(xc-nx0), dy=(yc-ny0); const double dc = std::sqrt((double)(dx*dx+dy*dy))*alpha + beta; float val = 0; cimg_forV(*this,k) { if (opacity>=1) { (*this)(xc,ny0,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))); (*this)(xc,ny1,0,k) = (T)(0.5f*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))); (*this)(nx0,yc,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))); (*this)(nx1,yc,0,k) = (T)(0.5f*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))); do { val = (float)(0.25f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) + (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand()); } while (val<(float)cimg::type::min() || val>(float)cimg::type::max()); (*this)(xc,yc,0,k) = (T)val; } else { const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); (*this)(xc,ny0,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k))*nopacity + copacity*(*this)(xc,ny0,0,k)); (*this)(xc,ny1,0,k) = (T)(0.5f*((*this)(nx0,ny1,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(xc,ny1,0,k)); (*this)(nx0,yc,0,k) = (T)(0.5f*((*this)(nx0,ny0,0,k)+(*this)(nx0,ny1,0,k))*nopacity + copacity*(*this)(nx0,yc,0,k)); (*this)(nx1,yc,0,k) = (T)(0.5f*((*this)(nx1,ny0,0,k)+(*this)(nx1,ny1,0,k))*nopacity + copacity*(*this)(nx1,yc,0,k)); do { val = (float)(0.25f*(((*this)(nx0,ny0,0,k)+(*this)(nx1,ny0,0,k) + (*this)(nx1,ny1,0,k)+(*this)(nx0,ny1,0,k)) + dc*cimg::grand())*nopacity + copacity*(*this)(xc,yc,0,k)); } while (val<(float)cimg::type::min() || val>(float)cimg::type::max()); (*this)(xc,yc,0,k) = (T)val; } } if (xc!=nx0 || yc!=ny0) { draw_plasma(nx0,ny0,xc,yc,alpha,beta,opacity); draw_plasma(xc,ny0,nx1,yc,alpha,beta,opacity); draw_plasma(nx0,yc,xc,ny1,alpha,beta,opacity); draw_plasma(xc,yc,nx1,ny1,alpha,beta,opacity); } } return *this; } //! Draw a plasma in the instance image. /** \param alpha = Alpha-parameter of the plasma. \param beta = Beta-parameter of the plasma. \param opacity = opacity of the drawing. **/ CImg& draw_plasma(const double alpha=1.0,const double beta=1.0,const float opacity=1) { return draw_plasma(0,0,width-1,height-1,alpha,beta,opacity); } //! Draw a 1D gaussian function in the instance image. /** \param xc = X-coordinate of the gaussian center. \param sigma = Standard variation of the gaussian distribution. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. **/ CImg& draw_gaussian(const float xc,const double sigma,const T *const color,const float opacity=1) { if (!is_empty()) { if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type()); const double sigma2 = 2*sigma*sigma; const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); const unsigned int whz = width*height*depth; const T *col = color; cimg_forX(*this,x) { const float dx = (x-xc); const double val = std::exp( -dx*dx/sigma2 ); T *ptrd = ptr(x,0,0,0); if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } col-=dim; } } return *this; } //! Draw an anisotropic 2D gaussian function in the instance image. /** \param xc = X-coordinate of the gaussian center. \param yc = Y-coordinate of the gaussian center. \param tensor = 2x2 covariance matrix. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. **/ template CImg& draw_gaussian(const float xc,const float yc,const CImg& tensor, const T *const color,const float opacity=1) { if (!is_empty()) { if (tensor.width!=2 || tensor.height!=2 || tensor.depth!=1 || tensor.dim!=1) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 2x2 matrix.", pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data); if (!color) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Specified color is (null)",pixel_type()); const CImg invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0); const t &a=invT2(0,0), &b=2*invT2(1,0), &c=invT2(1,1); const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); const unsigned int whz = width*height*depth; const T *col = color; float dy = -yc; cimg_forY(*this,y) { float dx = -xc; cimg_forX(*this,x) { const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy); T *ptrd = ptr(x,y,0,0); if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } col-=dim; dx++; } dy++; } } return *this; } //! Draw an isotropic 2D gaussian function in the instance image /** \param xc = X-coordinate of the gaussian center. \param yc = Y-coordinate of the gaussian center. \param sigma = standard variation of the gaussian distribution. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. **/ CImg& draw_gaussian(const float xc,const float yc,const float sigma,const T *const color,const float opacity=1) { return draw_gaussian(xc,yc,CImg::diagonal(sigma,sigma),color,opacity); } //! Draw an anisotropic 3D gaussian function in the instance image. /** \param xc = X-coordinate of the gaussian center. \param yc = Y-coordinate of the gaussian center. \param zc = Z-coordinate of the gaussian center. \param tensor = 3x3 covariance matrix. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. **/ template CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg& tensor, const T *const color,const float opacity=1) { if (!is_empty()) { if (tensor.width!=3 || tensor.height!=3 || tensor.depth!=1 || tensor.dim!=1) throw CImgArgumentException("CImg<%s>::draw_gaussian() : Tensor parameter (%u,%u,%u,%u,%p) is not a 3x3 matrix.", pixel_type(),tensor.width,tensor.height,tensor.depth,tensor.dim,tensor.data); const CImg invT = tensor.get_inverse(), invT2 = (invT*invT)/(-2.0); const t a=invT(0,0), b=2*invT(1,0), c=2*invT(2,0), d=invT(1,1), e=2*invT(2,1), f=invT(2,2); const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); const unsigned int whz = width*height*depth; const T *col = color; cimg_forXYZ(*this,x,y,z) { const float dx = (x-xc), dy = (y-yc), dz = (z-zc); const double val = std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz); T *ptrd = ptr(x,y,z,0); if (opacity>=1) cimg_forV(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whz; } else cimg_forV(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + copacity*(*ptrd)); ptrd+=whz; } col-=dim; } } return *this; } //! Draw an isotropic 3D gaussian function in the instance image /** \param xc = X-coordinate of the gaussian center. \param yc = Y-coordinate of the gaussian center. \param zc = Z-coordinate of the gaussian center. \param sigma = standard variation of the gaussian distribution. \param color = array of dimv() values of type \c T, defining the drawing color. \param opacity = opacity of the drawing. **/ CImg& draw_gaussian(const float xc,const float yc,const float zc, const double sigma,const T *const color,const float opacity=1) { return draw_gaussian(xc,yc,zc,CImg::diagonal(sigma,sigma,sigma),color,opacity); } //! Draw a 3D object in the instance image /** \param X = X-coordinate of the 3d object position \param Y = Y-coordinate of the 3d object position \param Z = Z-coordinate of the 3d object position \param points = Image N*3 describing 3D point coordinates \param primitives = List of P primitives \param colors = List of P color (or textures) \param opacities = Image of P opacities \param render_type = Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud) \param double_sided = Tell if object faces have two sides or are oriented. \param focale = length of the focale \param lightx = X-coordinate of the light \param lighty = Y-coordinate of the light \param lightz = Z-coordinate of the light \param ambient_light = Brightness (between 0..1) of the ambient light **/ template CImg& draw_object3d(const float X, const float Y, const float Z, const CImg& points, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float ambient_light=0.05f) { static CImg light_texture; if (is_empty() || !points || !primitives) return *this; if (!colors || !opacities) throw CImgArgumentException("CImg<%s>::draw_object3d() : Undefined colors or opacities",pixel_type()); if (points.height<3) return draw_object3d(X,Y,Z,points.get_resize(-100,3,1,1,0),primitives,colors,opacities, render_type,double_sided,focale,lightx,lighty,lightz,ambient_light); // Create light texture for phong-like rendering if (render_type==5) { if (colors.size>primitives.size) light_texture = colors[primitives.size]; else { static float olightx=0, olighty=0, olightz=0, oambient_light=0; if (!light_texture || lightx!=olightx || lighty!=olighty || lightz!=olightz || ambient_light!=oambient_light) { light_texture.assign(512,512); const float white[1]={ 1.0f }, dlx = lightx-X, dly = lighty-Y, dlz = lightz-Z, nl = (float)std::sqrt(dlx*dlx+dly*dly+dlz*dlz), nlx = light_texture.width/2*(1+dlx/nl), nly = light_texture.height/2*(1+dly/nl); (light_texture.draw_gaussian(nlx,nly,light_texture.width/3.0f,white)+=ambient_light).cut(0.0f,1.0f); olightx = lightx; olighty = lighty; olightz = lightz; oambient_light = ambient_light; } } } // Compute 3D to 2D projection CImg projections(points.width,2); cimg_forX(points,l) { const float x = (float)points(l,0), y = (float)points(l,1), z = (float)points(l,2); const float projectedz = z + Z + focale; projections(l,1) = Y + focale*y/projectedz; projections(l,0) = X + focale*x/projectedz; } // Compute and sort visible primitives CImg visibles(primitives.size); CImg zrange(primitives.size); unsigned int nb_visibles = 0; const float zmin = -focale+1.5f; { cimglist_for(primitives,l) { const CImg& primitive = primitives[l]; switch (primitive.size()) { case 1: { // Point const unsigned int i0 = (unsigned int)primitive(0); const float x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)); if (z0>zmin && x0>=0 && x0=0 && y0zmin && z1>zmin && xM>=0 && xm=0 && ymxM) xM = x2; if (y0yM) yM = y2; if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm=0 && ymxM) xM = x2; if (x3xM) xM = x3; if (y0yM) yM = y2; if (y3yM) yM = y3; if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm=0 && ym::draw_object3d() : Primitive %u is invalid (size = %u, can be 1,2,3,4,6,9 or 12)", pixel_type(),l,primitive.size()); }} } if (nb_visibles<=0) return *this; CImg permutations; CImg(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false); // Compute light properties CImg lightprops; switch (render_type) { case 3: { // Flat Shading lightprops.assign(nb_visibles); cimg_forX(lightprops,l) { const CImg& primitive = primitives(visibles(permutations(l))); const unsigned int psize = primitive.size(); if (psize==3 || psize==4 || psize==9 || psize==12) { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2); const float x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2), x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2), x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2), dx1 = x1-x0, dy1 = y1-y0, dz1 = z1-z0, dx2 = x2-x0, dy2 = y2-y0, dz2 = z2-z0, nx = dy1*dz2-dz1*dy2, ny = dz1*dx2-dx1*dz2, nz = dx1*dy2-dy1*dx2, norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), lx = X+(x0+x1+x2)/3-lightx, ly = Y+(y0+y1+y2)/3-lighty, lz = Z+(z0+z1+z2)/3-lightz, nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz), factor = cimg::abs(-lx*nx-ly*ny-lz*nz)/(norm*nl); lightprops[l] = cimg::min(cimg::max(factor,0.0f)+ambient_light,1.0f); } else lightprops[l] = 1.0f; } } break; case 4: // Gouraud Shading case 5: { // Phong-Shading CImg points_normals(points.width,double_sided?7:3,1,1,0); for (unsigned int l=0; l& primitive = primitives[visibles(l)]; const unsigned int psize = primitive.size(); const bool triangle_flag = (psize==3) || (psize==9), rectangle_flag = (psize==4) || (psize==12); if (triangle_flag || rectangle_flag) { const unsigned int i0 = (unsigned int)primitive(0), i1 = (unsigned int)primitive(1), i2 = (unsigned int)primitive(2), i3 = rectangle_flag?(unsigned int)primitive(3):0; const float x0 = (float)points(i0,0), y0 = (float)points(i0,1), z0 = (float)points(i0,2), x1 = (float)points(i1,0), y1 = (float)points(i1,1), z1 = (float)points(i1,2), x2 = (float)points(i2,0), y2 = (float)points(i2,1), z2 = (float)points(i2,2), dx1 = x1-x0, dy1 = y1-y0, dz1 = z1-z0, dx2 = x2-x0, dy2 = y2-y0, dz2 = z2-z0, nnx = dy1*dz2-dz1*dy2, nny = dz1*dx2-dx1*dz2, nnz = dx1*dy2-dy1*dx2, norm = 1e-5f + (float)std::sqrt(nnx*nnx+nny*nny+nnz*nnz), nx = nnx/norm, ny = nny/norm, nz = nnz/norm; if (double_sided) { unsigned int ind = nz>0?3U:0U; const float incr = nz>0?-1.0f:1.0f; points_normals(i0, ind)+=nx; points_normals(i1,ind)+=nx; points_normals(i2,ind)+=nx; points_normals(i0,++ind)+=ny; points_normals(i1,ind)+=ny; points_normals(i2,ind)+=ny; points_normals(i0,++ind)+=nz; points_normals(i1,ind)+=nz; points_normals(i2,ind)+=nz; points_normals(i0,6)+=incr; points_normals(i1,6)+=incr; points_normals(i2,6)+=incr; if (rectangle_flag) { points_normals(i3,ind)+=nz; points_normals(i3,--ind)+=ny; points_normals(i3,--ind)+=nz; points_normals(i3,6)+=incr; } } else { points_normals(i0,0)+=nx; points_normals(i0,1)+=ny; points_normals(i0,2)+=nz; points_normals(i1,0)+=nx; points_normals(i1,1)+=ny; points_normals(i1,2)+=nz; points_normals(i2,0)+=nx; points_normals(i2,1)+=ny; points_normals(i2,2)+=nz; if (rectangle_flag) { points_normals(i3,0)+=nx; points_normals(i3,1)+=ny; points_normals(i3,2)+=nz; } } } } if (double_sided) cimg_forX(points_normals,l) if (points_normals(l,6)<0) { points_normals(l,0) = -points_normals(l,3); points_normals(l,1) = -points_normals(l,4); points_normals(l,2) = -points_normals(l,5); } if (render_type==4) { lightprops.assign(points.width); cimg_forX(points,ll) { const float nx = points_normals(ll,0), ny = points_normals(ll,1), nz = points_normals(ll,2), norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), lx = (float)(X+points(ll,0)-lightx), ly = (float)(Y+points(ll,1)-lighty), lz = (float)(Z+points(ll,2)-lightz), nl = (float)std::sqrt(1e-5f+lx*lx+ly*ly+lz*lz), factor = (-lx*nx-ly*ny-lz*nz)/(norm*nl), nfactor = cimg::max(factor,0.0f); lightprops[ll] = cimg::min(nfactor+ambient_light,1.0f); } } else { const unsigned int lw2 = light_texture.width/2-1, lh2 = light_texture.height/2-1; lightprops.assign(points.width,2); cimg_forX(points,ll) { const float nx = points_normals(ll,0), ny = points_normals(ll,1), nz = points_normals(ll,2), norm = (float)std::sqrt(1e-5f+nx*nx+ny*ny+nz*nz), nnx = nx/norm, nny = ny/norm; lightprops(ll,0) = lw2*(1+nnx); lightprops(ll,1) = lh2*(1+nny); } } } break; } // Draw visible primitives const unsigned int opacsize = opacities.size; { for (unsigned int l=0; l& primitive = primitives[n_primitive]; const CImg& color = colors[n_primitive%colors.size]; const CImg& opacity = opacities[n_primitive%opacsize]; const float opac = opacity.size()?(float)opacity(0):1.0f; switch (primitive.size()) { case 1: { // colored point or sprite const unsigned int n0 = (unsigned int)primitive[0]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1); if (color.size()==dim) draw_point(x0,y0,color.ptr(),opac); else { const float z = Z + points(n0,2); const int factor = (int)(focale*100/(z+focale)); const int sw = color.width*factor/200, sh = color.height*factor/200; if (x0+sw>=0 && x0-sw<(int)width && y0+sh>=0 && y0-sh<(int)height) { const CImg sprite = color.get_resize(-factor,-factor,1,-100,render_type<=3?1:3); if (opacity.width==color.width && opacity.height==color.height) draw_image(sprite,opacity.get_resize(sprite.width,sprite.height,1,sprite.dim,1),x0-sw,y0-sh,0,0); else draw_image(sprite,x0-sw,y0-sh,0,0,opac); } } } break; case 2: { // colored line const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); if (render_type) draw_line(x0,y0,x1,y1,color.ptr(),~0L,opac); else draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac); } break; case 6: { // textured line const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], tx0 = (unsigned int)primitive[2], ty0 = (unsigned int)primitive[3], tx1 = (unsigned int)primitive[4], ty1 = (unsigned int)primitive[5]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1); if (render_type) draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac); else draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac). draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac); } break; case 3: { // colored triangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); switch(render_type) { case 0: draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac).draw_point(x2,y2,color.ptr(),opac); break; case 1: draw_line(x0,y0,x1,y1,color.ptr(),~0L,opac).draw_line(x0,y0,x2,y2,color.ptr(),~0L,opac). draw_line(x1,y1,x2,y2,color.ptr(),~0L,opac); break; case 2: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac); break; case 3: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac,lightprops(l)); break; case 4: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprops(n0),lightprops(n1),lightprops(n2),opac); break; case 5: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture, (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1), (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1), (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1), opac); break; } } break; case 4: { // colored rectangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], n3 = (unsigned int)primitive[3]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); switch(render_type) { case 0: draw_point(x0,y0,color.ptr(),opac).draw_point(x1,y1,color.ptr(),opac). draw_point(x2,y2,color.ptr(),opac).draw_point(x3,y3,color.ptr(),opac); break; case 1: draw_line(x0,y0,x1,y1,color.ptr(),~0L,opac).draw_line(x1,y1,x2,y2,color.ptr(),~0L,opac). draw_line(x2,y2,x3,y3,color.ptr(),~0L,opac).draw_line(x3,y3,x0,y0,color.ptr(),~0L,opac); break; case 2: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac).draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opac); break; case 3: draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),opac,lightprops(l)). draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),opac,lightprops(l)); break; case 4: { const float lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),lightprop0,lightprop1,lightprop2,opac). draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),lightprop0,lightprop2,lightprop3,opac); } break; case 5: { const unsigned int lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); draw_triangle(x0,y0,x1,y1,x2,y2,color.ptr(),light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). draw_triangle(x0,y0,x2,y2,x3,y3,color.ptr(),light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); } break; } } break; case 9: { // Textured triangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], tx0 = (unsigned int)primitive[3], ty0 = (unsigned int)primitive[4], tx1 = (unsigned int)primitive[5], ty1 = (unsigned int)primitive[6], tx2 = (unsigned int)primitive[7], ty2 = (unsigned int)primitive[8]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1); switch(render_type) { case 0: draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac). draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac). draw_point(x2,y2,color.get_vector_at(tx2,ty2).ptr(),opac); break; case 1: draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac). draw_line(x0,y0,x2,y2,color,tx0,ty0,tx2,ty2,opac). draw_line(x1,y1,x2,y2,color,tx1,ty1,tx2,ty2,opac); break; case 2: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac); break; case 3: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)); break; case 4: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprops(n0),lightprops(n1),lightprops(n2),opac); break; case 5: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, (unsigned int)lightprops(n0,0), (unsigned int)lightprops(n0,1), (unsigned int)lightprops(n1,0), (unsigned int)lightprops(n1,1), (unsigned int)lightprops(n2,0), (unsigned int)lightprops(n2,1), opac); break; } } break; case 12: { // Textured rectangle const unsigned int n0 = (unsigned int)primitive[0], n1 = (unsigned int)primitive[1], n2 = (unsigned int)primitive[2], n3 = (unsigned int)primitive[3], tx0 = (unsigned int)primitive[4], ty0 = (unsigned int)primitive[5], tx1 = (unsigned int)primitive[6], ty1 = (unsigned int)primitive[7], tx2 = (unsigned int)primitive[8], ty2 = (unsigned int)primitive[9], tx3 = (unsigned int)primitive[10], ty3 = (unsigned int)primitive[11]; const int x0 = (int)projections(n0,0), y0 = (int)projections(n0,1), x1 = (int)projections(n1,0), y1 = (int)projections(n1,1), x2 = (int)projections(n2,0), y2 = (int)projections(n2,1), x3 = (int)projections(n3,0), y3 = (int)projections(n3,1); switch(render_type) { case 0: draw_point(x0,y0,color.get_vector_at(tx0,ty0).ptr(),opac). draw_point(x1,y1,color.get_vector_at(tx1,ty1).ptr(),opac). draw_point(x2,y2,color.get_vector_at(tx2,ty2).ptr(),opac). draw_point(x3,y3,color.get_vector_at(tx3,ty3).ptr(),opac); break; case 1: draw_line(x0,y0,x1,y1,color,tx0,ty0,tx1,ty1,opac). draw_line(x1,y1,x2,y2,color,tx1,ty1,tx2,ty2,opac). draw_line(x2,y2,x3,y3,color,tx2,ty2,tx3,ty3,opac). draw_line(x3,y3,x0,y0,color,tx3,ty3,tx0,ty0,opac); break; case 2: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac). draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac); break; case 3: draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,opac,lightprops(l)). draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,opac,lightprops(l)); break; case 4: { const float lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,lightprop0,lightprop1,lightprop2,opac). draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx2,ty2,tx3,ty3,lightprop0,lightprop2,lightprop3,opac); } break; case 5: { const unsigned int lx0 = (unsigned int)lightprops(n0,0), ly0 = (unsigned int)lightprops(n0,1), lx1 = (unsigned int)lightprops(n1,0), ly1 = (unsigned int)lightprops(n1,1), lx2 = (unsigned int)lightprops(n2,0), ly2 = (unsigned int)lightprops(n2,1), lx3 = (unsigned int)lightprops(n3,0), ly3 = (unsigned int)lightprops(n3,1); draw_triangle(x0,y0,x1,y1,x2,y2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opac). draw_triangle(x0,y0,x2,y2,x3,y3,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opac); } break; } } break; } } } return *this; } //! Draw a 3D object in the instance image template CImg& draw_object3d(const float X, const float Y, const float Z, const CImgList& points, const CImgList& primitives, const CImgList& colors, const CImgList& opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float ambient_light=0.05f) { if (!points) return *this; CImg npoints(points.size,3,1,1,0); tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); cimg_forX(npoints,l) { const CImg& point = points[l]; const unsigned int siz = point.size(); if (!siz) throw CImgArgumentException("CImg<%s>::draw_object3d() : Given points (size=%u) contains a null element at " "position %u.",pixel_type(),points.size,l); *(ptrZ++) = (siz>2)?point(2):0; *(ptrY++) = (siz>1)?point(1):0; *(ptrX++) = point(0); } return draw_object3d(X,Y,Z,npoints,primitives,colors,opacities, render_type,double_sided,focale,lightx,lighty,lightz,ambient_light); } //! Draw a 3D object in the instance image template CImg& draw_object3d(const float X, const float Y, const float Z, const CImg& points, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float ambient_light=0.05f) { CImgList nopacities(opacities.size(),1); cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); return draw_object3d(X,Y,Z,points,primitives,colors,nopacities, render_type,double_sided,focale,lightx,lighty,lightz,ambient_light); } //! Draw a 3D object in the instance image template CImg& draw_object3d(const float X, const float Y, const float Z, const CImgList& points, const CImgList& primitives, const CImgList& colors, const CImg& opacities, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float ambient_light=0.05f) { CImgList nopacities(opacities.size(),1); { cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); } if (!points) return *this; CImg npoints(points.size,3,1,1,0); tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); cimg_forX(npoints,l) { const CImg& point = points[l]; const unsigned int siz = point.size(); if (!siz) throw CImgArgumentException("CImg<%s>::draw_object3d() : Given points (size=%u) contains a null element at " "position %u.",pixel_type(),points.size,l); *(ptrZ++) = (siz>2)?point(2):0; *(ptrY++) = (siz>1)?point(1):0; *(ptrX++) = point(0); } return draw_object3d(X,Y,Z,npoints,primitives,colors,nopacities, render_type,double_sided,focale,lightx,lighty,lightz,ambient_light); } //! Draw a 3D object in the instance image template CImg& draw_object3d(const float X, const float Y, const float Z, const tp& points, const CImgList& primitives, const CImgList& colors, const unsigned int render_type=4, const bool double_sided=false, const float focale=500, const float lightx=0, const float lighty=0, const float lightz=-5000, const float ambient_light=0.05f, const float opacity=1.0f) { return draw_object3d(X,Y,Z,points,primitives,colors, CImg(primitives.size,1,1,1,opacity), render_type,double_sided,focale,lightx,lighty,lightz, ambient_light); } //! Rescale and center a 3D object CImg& resize_object3d(const float siz=100, const bool centering=true) { T *ptrx = ptr(0,0), *ptry = ptr(0,1), *ptrz = ptr(0,2); float xm = (float)*(ptrx++), ym = (float)*(ptry++), zm = (float)*(ptrz++), xM = xm, yM = ym, zM = zm; for (unsigned int p=1; pxM) xM = x; if (y>yM) yM = y; if (z>zM) zM = z; } const float cx = 0.5f*(xm+xM), cy = 0.5f*(ym+yM), cz = 0.5f*(zm+zM), delta = cimg::max(xM-xm,yM-ym,zM-zm), ratio = (siz>=0)?(delta<=0?0:(siz/delta)):-siz/100; ptrx = ptr(0,0); ptry = ptr(0,1); ptrz = ptr(0,2); if (centering) cimg_forX(*this,l) { T &x = *(ptrx++), &y = *(ptry++), &z = *(ptrz++); x = (T)((x-cx)*ratio); y = (T)((y-cy)*ratio); z = (T)((z-cz)*ratio); } else cimg_forX(*this,l) { T &x = *(ptrx++), &y = *(ptry++), &z = *(ptrz++); x = (T)(cx+(x-cx)*ratio); y = (T)(cy+(y-cy)*ratio); z = (T)(cz+(z-cz)*ratio); } return *this; } //! Get a rescaled and centered version of the 3D object CImg get_resize_object3d(const float siz=100, const bool centering=true) const { return CImg(*this,false).resize_object3d(siz,centering); } //@} //---------------------------- // //! \name Image Filtering //@{ //---------------------------- //! Compute the correlation of the instance image by a mask. /** The correlation of the instance image \p *this by the mask \p mask is defined to be : res(x,y,z) = sum_{i,j,k} (*this)(x+i,y+j,z+k)*mask(i,j,k) \param mask = the correlation kernel. \param cond = the border condition type (0=zero, 1=dirichlet) \param weighted_correl = enable local normalization. **/ template CImg::type> get_correlate(const CImg& mask,const unsigned int cond=1,const bool weighted_correl=false) const { typedef typename cimg::largest::type restype; typedef typename cimg::largest::type fftype; typedef typename cimg::largest::type ftype; if (is_empty()) return CImg(); if (!mask || mask.dim!=1) throw CImgArgumentException("CImg<%s>::correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); CImg dest(width,height,depth,dim); if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // A special optimization is done for 2x2,3x3,4x4,5x5,2x2x2 and 3x3x3 mask (with cond=1) switch (mask.depth) { case 3: { CImg_3x3x3(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3x3(I,mask); else cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum3x3x3(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3x3(I,mask)/std::sqrt(norm)):0; } } break; case 2: { CImg_2x2x2(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2x2(I,mask); else cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum2x2x2(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2x2(I,mask)/std::sqrt(norm)):0; } } break; default: case 1: switch (mask.width) { case 5: { CImg_5x5(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr5x5(I,mask); else cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum5x5(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr5x5(I,mask)/std::sqrt(norm)):0; } } break; case 4: { CImg_4x4(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr4x4(I,mask); else cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum4x4(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr4x4(I,mask)/std::sqrt(norm)):0; } } break; case 3: { CImg_3x3(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr3x3(I,mask); else cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum3x3(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr3x3(I,mask)/std::sqrt(norm)):0; } } break; case 2: { CImg_2x2(I,T); if (!weighted_correl) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_corr2x2(I,mask); else cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum2x2(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_corr2x2(I,mask)/std::sqrt(norm)):0; } } break; case 1: (dest.assign(*this))*=mask(0); break; } } } else { // Generic version for other masks const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2); cimg_forV(*this,v) if (!weighted_correl) { // Classical correlation for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) val+= pix3d(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0); dest(x,y,z,v)=(restype)val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) val+= pix3d(x+xm,y+ym,z+zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0); dest(x,y,z,v)=(restype)val; } } else { // Weighted correlation for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0, norm = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { const T cval = pix3d(x+xm,y+ym,z+zm,v); val+= cval*mask(cxm+xm,cym+ym,czm+zm,0); norm+=cval*cval; } dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt((double)norm)):0; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0, norm = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { const T cval = pix3d(x+xm,y+ym,z+zm,v,0); val+= cval*mask(cxm+xm,cym+ym,czm+zm,0); norm+= cval*cval; } dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt((double)norm)):0; } } } return dest; } //! Correlate the image by a mask /** This is the in-place version of get_correlate. \see get_correlate **/ template CImg& correlate(const CImg& mask,const unsigned int cond=1,const bool weighted_correl=false) { return get_correlate(mask,cond,weighted_correl).swap(*this); } //! Return the convolution of the image by a mask /** The result \p res of the convolution of an image \p img by a mask \p mask is defined to be : res(x,y,z) = sum_{i,j,k} img(x-i,y-j,z-k)*mask(i,j,k) \param mask = the correlation kernel. \param cond = the border condition type (0=zero, 1=dirichlet) \param weighted_convol = enable local normalization. **/ template CImg::type> get_convolve(const CImg& mask, const unsigned int cond=1, const bool weighted_convol=false) const { typedef typename cimg::largest::type restype; typedef typename cimg::largest::type fftype; typedef typename cimg::largest::type ftype; if (is_empty()) return CImg(); if (!mask || mask.dim!=1) throw CImgArgumentException("CImg<%s>::convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); CImg dest(width,height,depth,dim); if (cond && mask.width==mask.height && ((mask.depth==1 && mask.width<=5) || (mask.depth==mask.width && mask.width<=3))) { // optimized version switch (mask.depth) { case 3: { CImg_3x3x3(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv3x3x3(I,mask); else cimg_forZV(*this,z,v) cimg_for3x3x3(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum3x3x3(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3x3(I,mask)/std::sqrt(norm)):0; } } break; case 2: { CImg_2x2x2(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv2x2x2(I,mask); else cimg_forZV(*this,z,v) cimg_for2x2x2(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum2x2x2(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2x2(I,mask)/std::sqrt(norm)):0; } } break; default: case 1: switch (mask.width) { case 5: { CImg_5x5(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) dest(x,y,z,v) = cimg_conv5x5(I,mask); else cimg_forZV(*this,z,v) cimg_for5x5(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum5x5(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv5x5(I,mask)/std::sqrt(norm)):0; } } break; case 4: { CImg_4x4(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv4x4(I,mask); else cimg_forZV(*this,z,v) cimg_for4x4(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum4x4(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv4x4(I,mask)/std::sqrt(norm)):0; } } break; case 3: { CImg_3x3(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv3x3(I,mask); else cimg_forZV(*this,z,v) cimg_for3x3(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum3x3(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv3x3(I,mask)/std::sqrt(norm)):0; } } break; case 2: { CImg_2x2(I,T); if (!weighted_convol) cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) dest(x,y,z,v) = (T)cimg_conv2x2(I,mask); else cimg_forZV(*this,z,v) cimg_for2x2(*this,x,y,z,v,I) { const double norm = (double)cimg_squaresum2x2(I); dest(x,y,z,v) = (norm!=0)?(restype)(cimg_conv2x2(I,mask)/std::sqrt(norm)):0; } } break; case 1: (dest.assign(*this))*=mask(0); break; } } } else { // generic version const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2); cimg_forV(*this,v) if (!weighted_convol) { // Classical convolution for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) val+= pix3d(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0); dest(x,y,z,v)=(restype)val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) val+= pix3d(x-xm,y-ym,z-zm,v,0)*mask(cxm+xm,cym+ym,czm+zm,0); dest(x,y,z,v)=(restype)val; } } else { // Weighted convolution for (int z=czm; z=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { ftype val = 0, norm = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { const T cval = pix3d(x-xm,y-ym,z-zm,v); val+= cval*mask(cxm+xm,cym+ym,czm+zm,0); norm+=cval*cval; } dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt(norm)):0; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { double val = 0, norm = 0; for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) { const T cval = pix3d(x-xm,y-ym,z-zm,v,0); val+= cval*mask(cxm+xm,cym+ym,czm+zm,0); norm+= cval*cval; } dest(x,y,z,v)=(norm!=0)?(restype)(val/std::sqrt(norm)):0; } } } return dest; } //! Convolve the image by a mask /** This is the in-place version of get_convolve(). \see get_convolve() **/ template CImg& convolve(const CImg& mask,const unsigned int cond=1,const bool weighted_convol=false) { return get_convolve(mask,cond,weighted_convol).swap(*this); } //! Return the erosion of the image by a structuring element. template CImg::type> get_erode(const CImg& mask, const unsigned int cond=1, const bool weighted_erosion=false) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); if (!mask || mask.dim!=1) throw CImgArgumentException("CImg<%s>::erode() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); CImg dest(width,height,depth,dim); const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2); cimg_forV(*this,v) if (!weighted_erosion) { // Classical erosion for (int z=czm; z::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)(*this)(x+xm,y+ym,z+zm,v),min_val); dest(x,y,z,v)=min_val; } if (cond) cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype min_val = cimg::type::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v),min_val); dest(x,y,z,v)=min_val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype min_val = cimg::type::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) min_val = cimg::min((restype)pix3d(x+xm,y+ym,z+zm,v,0),min_val); dest(x,y,z,v)=min_val; } } else { // Weighted erosion t mval=0; for (int z=czm; z::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)((*this)(x+xm,y+ym,z+zm,v)+mval),min_val); dest(x,y,z,v)=min_val; } if (cond) cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype min_val = cimg::type::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v)+mval),min_val); dest(x,y,z,v)=min_val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype min_val = cimg::type::max(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) min_val = cimg::min((restype)(pix3d(x+xm,y+ym,z+zm,v,0)+mval),min_val); dest(x,y,z,v)=min_val; } } return dest; } //! Erode the image by a structuring element /** This is the in-place version of get_erode(). \see get_erode() **/ template CImg& erode(const CImg& mask,const unsigned int cond=1,const bool weighted_erosion=false) { return get_erode(mask,cond,weighted_erosion).swap(*this); } //! Erode the image by a square structuring element of size n CImg get_erode(const unsigned int n, const unsigned int cond=1) const { static CImg mask; if (mask.width!=n) mask.assign(n,n,1,1,1); const CImg res = get_erode(mask,cond,false); if (n>20) mask.assign(); return res; } //! Erode the image by a square structuring element of size n CImg& erode(const unsigned int n, const unsigned int cond=1) { return get_erode(n,cond).swap(*this); } //! Return the dilatation of the image by a structuring element. template CImg::type> get_dilate(const CImg& mask, const unsigned int cond=1, const bool weighted_dilatation=false) const { typedef typename cimg::largest::type restype; if (is_empty()) return CImg(); if (!mask || mask.dim!=1) throw CImgArgumentException("CImg<%s>::dilate() : Specified mask (%u,%u,%u,%u,%p) is not a scalar image.", pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); CImg dest(width,height,depth,dim); const int cxm=mask.width/2, cym=mask.height/2, czm=mask.depth/2, fxm=cxm-1+(mask.width%2), fym=cym-1+(mask.height%2), fzm=czm-1+(mask.depth%2); cimg_forV(*this,v) if (!weighted_dilatation) { // Classical dilatation for (int z=czm; z::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)(*this)(x+xm,y+ym,z+zm,v),max_val); dest(x,y,z,v)=max_val; } if (cond) cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype max_val = cimg::type::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v),max_val); dest(x,y,z,v)=max_val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype max_val = cimg::type::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if (mask(cxm+xm,cym+ym,czm+zm,0)) max_val = cimg::max((restype)pix3d(x+xm,y+ym,z+zm,v,0),max_val); dest(x,y,z,v)=max_val; } } else { // Weighted dilatation t mval=0; for (int z=czm; z::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)((*this)(x+xm,y+ym,z+zm,v)-mval),max_val); dest(x,y,z,v)=max_val; } if (cond) cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype max_val = cimg::type::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v)-mval),max_val); dest(x,y,z,v)=max_val; } else cimg_forYZV(*this,y,z,v) for (int x=0; x=dimy()-cym || z=dimz()-czm)?x++:((x=dimx()-cxm)?x++:(x=dimx()-cxm))) { restype max_val = cimg::type::min(); for (int zm=-czm; zm<=fzm; zm++) for (int ym=-cym; ym<=fym; ym++) for (int xm=-cxm; xm<=fxm; xm++) if ((mval=mask(cxm+xm,cym+ym,czm+zm,0))!=0) max_val = cimg::max((restype)(pix3d(x+xm,y+ym,z+zm,v,0)-mval),max_val); dest(x,y,z,v)=max_val; } } return dest; } //! Dilate the image by a structuring element /** This is the in-place version of get_dilate(). \see get_dilate() **/ template CImg& dilate(const CImg& mask,const unsigned int cond=1,const bool weighted_dilatation=false) { return get_dilate(mask,cond,weighted_dilatation).swap(*this); } //! Dilate the image by a square structuring element of size n CImg get_dilate(const unsigned int n, const unsigned int cond=1) const { static CImg mask; if (mask.width!=n) mask.assign(n,n,1,1,1); const CImg res = get_dilate(mask,cond,false); if (n>20) mask.assign(); return res; } //! Dilate the image by a square structuring element of size n CImg& dilate(const unsigned int n, const unsigned int cond=1) { return get_dilate(n,cond).swap(*this); } //! Add noise to the image /** This is the in-place version of get_noise. \see get_noise. **/ CImg& noise(const double sigma=-20, const unsigned int ntype=0) { if (!is_empty()) { double nsigma = sigma, max = (double)cimg::type::max(), min = (double)cimg::type::min(); static bool first_time = true; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } CImgStats st; if (nsigma==0) return *this; if (nsigma<0 || ntype==2) st = CImgStats(*this,false); if (nsigma<0) nsigma = -nsigma*(st.max-st.min)/100.0; switch (ntype) { case 0: { // Gaussian noise cimg_for(*this,ptr,T) { double val = *ptr+nsigma*cimg::grand(); if (val>max) val = max; if (valmax) val = max; if (val100.0) *ptr = (T)(unsigned int)((std::sqrt(z) * cimg::grand()) + z); else { unsigned int k = 0; const double y=std::exp(-z); for (double s=1.0; s>=y; k++) s *= cimg::rand(); *ptr=(T)(k-1); } } } } break; case 4: { // Rice noise const double sqrt2 = (double)std::sqrt(2.0); cimg_for(*this,ptr,T) { const double val0 = (double)*ptr/sqrt2, re = val0 + nsigma*cimg::grand(), im = val0 + nsigma*cimg::grand(); double val = std::sqrt(re*re + im*im); if (val>max) val = max; if (val=0; i--) { Y0=a3*I1+a4*I2+b1*Y1+b2*Y2; ima-=offset; \ I2=I1; I1=*ima; *ima=(T)(*(--Y)+Y0); Y2=Y1; Y1=Y0; } \ } //! Apply a deriche filter on the image /** This is the in-place version of get_deriche \see get_deriche. **/ CImg& deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) { if (!is_empty()) { if (sigma<0 || order<0 || order>2) throw CImgArgumentException("CImg<%s>::deriche() : Bad arguments (sigma=%g, order=%d)",pixel_type(),sigma,order); const float alpha=sigma>0?(1.695f/sigma):20,ea=(float)std::exp(alpha),ema=(float)std::exp(-alpha),em2a=ema*ema,b1=2*ema,b2=-em2a; float ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0; double *Y,Y0,Y1,Y2; int i,offset,nb; T *ima,I1,I2; switch(order) { case 1: // first derivative ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema); a1 = a4 = 0; a2 = ek*ema; a3 = -ek*ema; parity =-1; if (cond) { sumg1 = (ek*ea) / ((ea-1)*(ea-1)); g0 = 0; sumg0 = g0+sumg1; } else g0 = sumg0 = sumg1 = 0; break; case 2: // second derivative ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) ); ek = -(em2a-1)/(2*alpha*ema); a1 = ekn; a2 = -ekn*(1+ek*alpha)*ema; a3 = ekn*(1-ek*alpha)*ema; a4 = -ekn*em2a; parity =1; if (cond) { sumg1 = ekn/2; g0 = ekn; sumg0 = g0+sumg1; } else g0=sumg0=sumg1=0; break; default: // smoothing ek = (1-ema)*(1-ema) / (1+2*alpha*ema - em2a); a1 = ek; a2 = ek*ema*(alpha-1); a3 = ek*ema*(alpha+1); a4 = -ek*em2a; parity = 1; if (cond) { sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1)); g0 = ek; sumg0 = g0+sumg1; } else g0=sumg0=sumg1=0; break; } // filter init Y = new double[cimg::max(width,height,depth)]; switch(cimg::uncase(axe)) { case 'x': if (width>1) { offset = 1; nb = width; cimg_forYZV(*this,y,z,k) cimg_deriche_apply(0,y,z,k,nb,offset,T); } break; case 'y': if (height>1) { offset = width; nb = height; cimg_forXZV(*this,x,z,k) cimg_deriche_apply(x,0,z,k,nb,offset,T); } break; case 'z': if (depth>1) { offset = width*height; nb = depth; cimg_forXYV(*this,x,y,k) cimg_deriche_apply(x,y,0,k,nb,offset,T); } break; default: throw CImgArgumentException("CImg<%s>::deriche() : unknow axe '%c', must be 'x','y' or 'z'",pixel_type(),axe); } delete[] Y; } return *this; } //! Return the result of the Deriche filter /** The Canny-Deriche filter is a recursive algorithm allowing to compute blurred derivatives of order 0,1 or 2 of an image. \see blur **/ CImg get_deriche(const float sigma=1,const int order=0,const char axe='x',const unsigned int cond=1) const { return (+*this).deriche(sigma,order,axe,cond); } //! Blur the image with a Deriche filter (anisotropically) /** This is the in-place version of get_blur(). \see get_blur(). **/ CImg& blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) { if (!is_empty()) { if (width>1 && sigmax>0) deriche(sigmax,0,'x',cond); if (height>1 && sigmay>0) deriche(sigmay,0,'y',cond); if (depth>1 && sigmaz>0) deriche(sigmaz,0,'z',cond); } return *this; } //! Blur the image with a Canny-Deriche filter. /** This is the in-place version of get_blur(). **/ CImg& blur(const float sigma,const unsigned int cond=1) { return blur(sigma,sigma,sigma,cond); } //! Return a blurred version of the image, using a Canny-Deriche filter. /** Blur the image with an anisotropic exponential filter (Deriche filter of order 0). **/ CImg get_blur(const float sigmax,const float sigmay,const float sigmaz,const unsigned int cond=1) const { return (+*this).blur(sigmax,sigmay,sigmaz,cond); } //! Return a blurred version of the image, using a Canny-Deriche filter. CImg get_blur(const float sigma,const unsigned int cond=1) const { return (+*this).blur(sigma,cond); } //! Blur an image following a field of diffusion tensors. /** This is the in-place version of get_blur_anisotropic(). **/ template CImg& blur_anisotropic(const CImg& G, const float amplitude=60.0f, const float dl=0.8f,const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) { #define cimg_valign2d(i,j) \ { ftype &u = W(i,j,0,0), &v = W(i,j,0,1); \ if (u*curru + v*currv<0) { u=-u; v=-v; }} #define cimg_valign3d(i,j,k) \ { ftype &u = W(i,j,k,0), &v = W(i,j,k,1), &w = W(i,j,k,2); \ if (u*curru + v*currv + w*currw<0) { u=-u; v=-v; w=-w; }} // Check arguments and init variables typedef typename cimg::largest::type ftype; if (!is_empty() && amplitude>0) { if (!G || (G.dim!=3 && G.dim!=6) || G.width!=width || G.height!=height || G.depth!=depth) throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Specified tensor field (%u,%u,%u,%u) is not valid.", pixel_type(),G.width,G.height,G.depth,G.dim); const float sqrt2amplitude = (float)std::sqrt(2*amplitude); const bool threed = (G.dim>=6); const int dx1 = dimx()-1, dy1 = dimy()-1, dz1 = dimz()-1; CImg dest(width,height,depth,dim,0), W(width,height,depth,threed?4:3), tmp(dim); int N = 0; if (threed) // 3D version of the algorithm for (float phi=(180%(int)da)/2.0f; phi<=180; phi+=da) { const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)), da2 = datmp<1?360.0f:datmp; for (float theta=0; theta<360; (theta+=da2),N++) { const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)*std::cos(phir)), vy = (float)(std::sin(thetar)*std::cos(phir)), vz = (float)std::sin(phir); const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2), *pd = G.ptr(0,0,0,3), *pe = G.ptr(0,0,0,4), *pf = G.ptr(0,0,0,5); ftype *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2), *pd3 = W.ptr(0,0,0,3); cimg_forXYZ(G,xg,yg,zg) { const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++); const float u = (float)(a*vx + b*vy + c*vz), v = (float)(b*vx + d*vy + e*vz), w = (float)(c*vx + e*vy + f*vz), n = (float)std::sqrt(1e-5+u*u+v*v+w*w), dln = dl/n; *(pd0++) = (ftype)(u*dln); *(pd1++) = (ftype)(v*dln); *(pd2++) = (ftype)(w*dln); *(pd3++) = (ftype)n; } cimg_forXYZ(*this,x,y,z) { tmp.fill(0); const float cu = (float)W(x,y,z,0), cv = (float)W(x,y,z,1), cw = (float)W(x,y,z,2), n = (float)W(x,y,z,3), fsigma = (float)(n*sqrt2amplitude), length = gauss_prec*fsigma, fsigma2 = 2*fsigma*fsigma; float S = 0, pu = cu, pv = cv, pw = cw, X = (float)x, Y = (float)y, Z = (float)z; switch (interpolation) { case 0: { // Nearest neighbor for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const int cx = (int)(X+0.5f), cy = (int)(Y+0.5f), cz = (int)(Z+0.5f); float u = (float)W(cx,cy,cz,0), v = (float)W(cx,cy,cz,1), w = (float)W(cx,cy,cz,2); if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)(*this)(cx,cy,cz,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*(*this)(cx,cy,cz,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } } break; case 1: { // Linear interpolation for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const int cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1, cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1, cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1; const float curru = (float)W(cx,cy,cz,0), currv = (float)W(cx,cy,cz,1), currw = (float)W(cx,cy,cz,2); cimg_valign3d(px,py,pz); cimg_valign3d(cx,py,pz); cimg_valign3d(nx,py,pz); cimg_valign3d(px,cy,pz); cimg_valign3d(cx,cy,pz); cimg_valign3d(nx,cy,pz); cimg_valign3d(px,ny,pz); cimg_valign3d(cx,ny,pz); cimg_valign3d(nx,ny,pz); cimg_valign3d(px,py,cz); cimg_valign3d(cx,py,cz); cimg_valign3d(nx,py,cz); cimg_valign3d(px,cy,cz); cimg_valign3d(nx,cy,cz); cimg_valign3d(px,ny,cz); cimg_valign3d(cx,ny,cz); cimg_valign3d(nx,ny,cz); cimg_valign3d(px,py,nz); cimg_valign3d(cx,py,nz); cimg_valign3d(nx,py,nz); cimg_valign3d(px,cy,nz); cimg_valign3d(cx,cy,nz); cimg_valign3d(nx,cy,nz); cimg_valign3d(px,ny,nz); cimg_valign3d(cx,ny,nz); cimg_valign3d(nx,ny,nz); float u = (float)(W.linear_pix3d(X,Y,Z,0)), v = (float)(W.linear_pix3d(X,Y,Z,1)), w = (float)(W.linear_pix3d(X,Y,Z,2)); if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix3d(X,Y,Z,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix3d(X,Y,Z,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } } break; default: { // 2nd order Runge Kutta for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { const int cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1, cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1, cz = (int)Z, pz = (cz-1<0)?0:cz-1, nz = (cz+1>dz1)?dz1:cz+1; const float curru = (float)W(cx,cy,cz,0), currv = (float)W(cx,cy,cz,1), currw = (float)W(cx,cy,cz,2); cimg_valign3d(px,py,pz); cimg_valign3d(cx,py,pz); cimg_valign3d(nx,py,pz); cimg_valign3d(px,cy,pz); cimg_valign3d(cx,cy,pz); cimg_valign3d(nx,cy,pz); cimg_valign3d(px,ny,pz); cimg_valign3d(cx,ny,pz); cimg_valign3d(nx,ny,pz); cimg_valign3d(px,py,cz); cimg_valign3d(cx,py,cz); cimg_valign3d(nx,py,cz); cimg_valign3d(px,cy,cz); cimg_valign3d(nx,cy,cz); cimg_valign3d(px,ny,cz); cimg_valign3d(cx,ny,cz); cimg_valign3d(nx,ny,cz); cimg_valign3d(px,py,nz); cimg_valign3d(cx,py,nz); cimg_valign3d(nx,py,nz); cimg_valign3d(px,cy,nz); cimg_valign3d(cx,cy,nz); cimg_valign3d(nx,cy,nz); cimg_valign3d(px,ny,nz); cimg_valign3d(cx,ny,nz); cimg_valign3d(nx,ny,nz); const float u0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,0)), v0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,1)), w0 = (float)(0.5f*W.linear_pix3d(X,Y,Z,2)); float u = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,0)), v = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,1)), w = (float)(W.linear_pix3d(X+u0,Y+v0,Z+w0,2)); if ((pu*u + pv*v + pw*w)<0) { u=-u; v=-v; w=-w; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix3d(X,Y,Z,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix3d(X,Y,Z,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } } break; } if (S>0) cimg_forV(dest,k) dest(x,y,z,k)+=tmp[k]/S; else cimg_forV(dest,k) dest(x,y,z,k)+=(ftype)((*this)(x,y,z,k)); #ifdef cimg_plugin_greycstoration if (!*(greycstoration_params->stop_request)) (*greycstoration_params->counter)++; else return *this; #endif } } } else // 2D version of the algorithm for (float theta=(360%(int)da)/2.0f; theta<360; (theta+=da),N++) { const float thetar = (float)(theta*cimg::PI/180), vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar)); const t *pa = G.ptr(0,0,0,0), *pb = G.ptr(0,0,0,1), *pc = G.ptr(0,0,0,2); ftype *pd0 = W.ptr(0,0,0,0), *pd1 = W.ptr(0,0,0,1), *pd2 = W.ptr(0,0,0,2); cimg_forXY(G,xg,yg) { const t a = *(pa++), b = *(pb++), c = *(pc++); const float u = (float)(a*vx + b*vy), v = (float)(b*vx + c*vy), n = (float)std::sqrt(1e-5+u*u+v*v), dln = dl/n; *(pd0++) = (ftype)(u*dln); *(pd1++) = (ftype)(v*dln); *(pd2++) = (ftype)n; } cimg_forXY(*this,x,y) { tmp.fill(0); const float cu = (float)W(x,y,0,0), cv = (float)W(x,y,0,1), n = (float)W(x,y,0,2), fsigma = (float)(n*sqrt2amplitude), length = gauss_prec*fsigma, fsigma2 = 2*fsigma*fsigma; float S = 0, pu = cu, pv = cv, X = (float)x, Y = (float)y; switch (interpolation) { case 0: { // Nearest-neighbor interpolation for 2D images for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const int cx = (int)(X+0.5f), cy = (int)(Y+0.5f); float u = (float)W(cx,cy,0,0), v = (float)W(cx,cy,0,1); if ((pu*u + pv*v)<0) { u=-u; v=-v; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)(*this)(cx,cy,0,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*(*this)(cx,cy,0,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); } } break; case 1: { // Linear interpolation for 2D images for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const int cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1, cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1; const float curru = (float)W(cx,cy,0,0), currv = (float)W(cx,cy,0,1); cimg_valign2d(px,py); cimg_valign2d(cx,py); cimg_valign2d(nx,py); cimg_valign2d(px,cy); cimg_valign2d(nx,cy); cimg_valign2d(px,ny); cimg_valign2d(cx,ny); cimg_valign2d(nx,ny); float u = (float)(W.linear_pix2d(X,Y,0,0)), v = (float)(W.linear_pix2d(X,Y,0,1)); if ((pu*u + pv*v)<0) { u=-u; v=-v; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix2d(X,Y,0,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix2d(X,Y,0,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); } } break; default: { // 2nd-order Runge-kutta interpolation for 2D images for (float l=0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { const int cx = (int)X, px = (cx-1<0)?0:cx-1, nx = (cx+1>dx1)?dx1:cx+1, cy = (int)Y, py = (cy-1<0)?0:cy-1, ny = (cy+1>dy1)?dy1:cy+1; const float curru = (float)W(cx,cy,0,0), currv = (float)W(cx,cy,0,1); cimg_valign2d(px,py); cimg_valign2d(cx,py); cimg_valign2d(nx,py); cimg_valign2d(px,cy); cimg_valign2d(nx,cy); cimg_valign2d(px,ny); cimg_valign2d(cx,ny); cimg_valign2d(nx,ny); const float u0 = (float)(0.5f*W.linear_pix2d(X,Y,0,0)), v0 = (float)(0.5f*W.linear_pix2d(X,Y,0,1)); float u = (float)(W.linear_pix2d(X+u0,Y+v0,0,0)), v = (float)(W.linear_pix2d(X+u0,Y+v0,0,1)); if ((pu*u + pv*v)<0) { u=-u; v=-v; } if (fast_approx) { cimg_forV(*this,k) tmp[k]+=(ftype)linear_pix2d(X,Y,0,k); S++; } else { const float coef = (float)std::exp(-l*l/fsigma2); cimg_forV(*this,k) tmp[k]+=(ftype)(coef*linear_pix2d(X,Y,0,k)); S+=coef; } X+=(pu=u); Y+=(pv=v); } } break; } if (S>0) cimg_forV(dest,k) dest(x,y,0,k)+=tmp[k]/S; else cimg_forV(dest,k) dest(x,y,0,k)+=(ftype)((*this)(x,y,0,k)); #ifdef cimg_plugin_greycstoration if (!*(greycstoration_params->stop_request)) (*greycstoration_params->counter)++; else return *this; #endif } } const ftype *ptrs = dest.data+dest.size(); const T m = cimg::type::min(), M = cimg::type::max(); cimg_for(*this,ptrd,T) { const ftype val = *(--ptrs)/N; *ptrd = valM?M:(T)val); } } return *this; } //! Get a blurred version of an image following a field of diffusion tensors. /** \param G = Field of square roots of diffusion tensors used to drive the smoothing. \param amplitude = amplitude of the smoothing. \param dl = spatial discretization. \param da = angular discretization. \param gauss_prec = precision of the gaussian function. \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta) \param fast_approx = Tell to use the fast approximation or not. **/ template CImg get_blur_anisotropic(const CImg& G, const float amplitude=60.0f, const float dl=0.8f,const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true) const { return (+*this).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx); } //! Blur an image following a field of diffusion tensors. template CImg& blur_anisotropic(const CImg& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true, const float geom_factor=1.0f) { if (!is_empty() && amplitude>0) { if (amplitude==0) return *this; if (amplitude<0 || sharpness<0 || anisotropy<0 || anisotropy>1 || alpha<0 || sigma<0 || dl<0 || da<0 || gauss_prec<0) throw CImgArgumentException("CImg<%s>::blur_anisotropic() : Given parameters are amplitude(%g), sharpness(%g), " "anisotropy(%g), alpha(%g), sigma(%g), dl(%g), da(%g), gauss_prec(%g).\n" "Admissible parameters are in the range : amplitude>0, sharpness>0, anisotropy in [0,1], " "alpha>0, sigma>0, dl>0, da>0, gauss_prec>0.", pixel_type(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec); const bool threed = (depth>1), no_mask = mask.is_empty(); const float nsharpness = cimg::max(sharpness,1e-5f), power1 = 0.5f*nsharpness, power2 = power1/(1e-7f+1.0f-anisotropy); CImg blurred = CImg(*this,false).blur(alpha); if (geom_factor>0) blurred*=geom_factor; else blurred.normalize(0,-geom_factor); if (threed) { // Field for 3D volumes CImg val(3), vec(3,3), G(blurred.get_structure_tensorXYZ()); if (sigma>0) G.blur(sigma); cimg_forXYZ(*this,x,y,z) { if (no_mask || mask(x,y,z)) { G.get_tensor_at(x,y,z).symmetric_eigen(val,vec); const float l1 = val[2], l2 = val[1], l3 = val[0], ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), n1 = (float)std::pow(1.0f+l1+l2+l3,-power1), n2 = (float)std::pow(1.0f+l1+l2+l3,-power2); G(x,y,z,0) = n1*(ux*ux + vx*vx) + n2*wx*wx; G(x,y,z,1) = n1*(ux*uy + vx*vy) + n2*wx*wy; G(x,y,z,2) = n1*(ux*uz + vx*vz) + n2*wx*wz; G(x,y,z,3) = n1*(uy*uy + vy*vy) + n2*wy*wy; G(x,y,z,4) = n1*(uy*uz + vy*vz) + n2*wy*wz; G(x,y,z,5) = n1*(uz*uz + vz*vz) + n2*wz*wz; } 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; #ifdef cimg_plugin_greycstoration if (!*(greycstoration_params->stop_request)) (*greycstoration_params->counter)++; else return *this; #endif } blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx); } else { // Field for 2D images CImg val(2), vec(2,2), G(blurred.get_structure_tensorXY()); if (sigma>0) G.blur(sigma); cimg_forXY(*this,x,y) { if (no_mask || mask(x,y)) { G.get_tensor_at(x,y).symmetric_eigen(val,vec); const float l1 = val[1], l2 = val[0], ux = vec(1,0), uy = vec(1,1), vx = vec(0,0), vy = vec(0,1), n1 = (float)std::pow(1.0f+l1+l2,-power1), n2 = (float)std::pow(1.0f+l1+l2,-power2); G(x,y,0,0) = n1*ux*ux + n2*vx*vx; G(x,y,0,1) = n1*ux*uy + n2*vx*vy; G(x,y,0,2) = n1*uy*uy + n2*vy*vy; } else G(x,y,0,0) = G(x,y,0,1) = G(x,y,0,2) = 0; #ifdef cimg_plugin_greycstoration if (!*(greycstoration_params->stop_request)) (*greycstoration_params->counter)++; else return *this; #endif } blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation,fast_approx); } } return *this; } //! Blur an image in an anisotropic way. /** \param amplitude = amplitude of the anisotropic blur. \param sharpness = define the contour preservation. \param anisotropy = define the smoothing anisotropy. \param alpha = image pre-blurring (gaussian). \param sigma = regularity of the tensor-valued geometry. \param dl = spatial discretization. \param da = angular discretization. \param gauss_prec = precision of the gaussian function. \param interpolation Used interpolation scheme (0 = nearest-neighbor, 1 = linear, 2 = Runge-Kutta) \param fast_approx = Tell to use the fast approximation or not **/ template CImg get_blur_anisotropic(const CImg& mask, const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true, const float geom_factor=1.0f) const { return (+*this).blur_anisotropic(mask,amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor); } //! Blur an image following in an anisotropic way. CImg& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f,const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true, const float geom_factor=1.0f) { return blur_anisotropic(CImg(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor); } //! Blur an image following in an anisotropic way. CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.3f, const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30.0f, const float gauss_prec=2.0f, const unsigned int interpolation=0, const bool fast_approx=true, const float geom_factor=1.0f) const { return (+*this).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor); } //! Return the Fast Fourier Transform of an image (along a specified axis) CImgList::type> get_FFT(const char axe, const bool inverse=false) const { typedef typename cimg::largest::type restype; return CImgList(*this).FFT(axe,inverse); } //! Return the Fast Fourier Transform on an image CImgList::type> get_FFT(const bool inverse=false) const { typedef typename cimg::largest::type restype; return CImgList(*this).FFT(inverse); } //! Apply a median filter. CImg get_blur_median(const unsigned int n=3) { CImg res(width,height,depth,dim); if (!n || n==1) return *this; const int hl=n/2, hr=hl-1+n%2; if (res.depth!=1) { // 3D median filter CImg vois; cimg_forXYZV(*this,x,y,z,k) { vois = get_crop(x-hl,y-hl,z-hl,k,x+hr,y+hr,z+hr,k); res(x,y,z,k) = vois.median(); } } else { // 2D median filter #define _median_sort(a,b) if ((a)>(b)) cimg::swap(a,b) switch (n) { case 3: { CImg_3x3(I,T); CImg_3x3(J,T); cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { cimg_copy3x3(I,J); _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn); _median_sort(Jpp, Jcp); _median_sort(Jpc, Jcc); _median_sort(Jpn, Jcn); _median_sort(Jcp, Jnp); _median_sort(Jcc, Jnc); _median_sort(Jcn, Jnn); _median_sort(Jpp, Jpc); _median_sort(Jnc, Jnn); _median_sort(Jcc, Jcn); _median_sort(Jpc, Jpn); _median_sort(Jcp, Jcc); _median_sort(Jnp, Jnc); _median_sort(Jcc, Jcn); _median_sort(Jcc, Jnp); _median_sort(Jpn, Jcc); _median_sort(Jcc, Jnp); res(x,y,0,k) = Jcc; } } break; case 5: { CImg_5x5(I,T); CImg_5x5(J,T); cimg_forV(*this,k) cimg_for5x5(*this,x,y,0,k,I) { cimg_copy5x5(I,J); _median_sort(Jbb, Jpb); _median_sort(Jnb, Jab); _median_sort(Jcb, Jab); _median_sort(Jcb, Jnb); _median_sort(Jpp, Jcp); _median_sort(Jbp, Jcp); _median_sort(Jbp, Jpp); _median_sort(Jap, Jbc); _median_sort(Jnp, Jbc); _median_sort(Jnp, Jap); _median_sort(Jcc, Jnc); _median_sort(Jpc, Jnc); _median_sort(Jpc, Jcc); _median_sort(Jbn, Jpn); _median_sort(Jac, Jpn); _median_sort(Jac, Jbn); _median_sort(Jnn, Jan); _median_sort(Jcn, Jan); _median_sort(Jcn, Jnn); _median_sort(Jpa, Jca); _median_sort(Jba, Jca); _median_sort(Jba, Jpa); _median_sort(Jna, Jaa); _median_sort(Jcb, Jbp); _median_sort(Jnb, Jpp); _median_sort(Jbb, Jpp); _median_sort(Jbb, Jnb); _median_sort(Jab, Jcp); _median_sort(Jpb, Jcp); _median_sort(Jpb, Jab); _median_sort(Jpc, Jac); _median_sort(Jnp, Jac); _median_sort(Jnp, Jpc); _median_sort(Jcc, Jbn); _median_sort(Jap, Jbn); _median_sort(Jap, Jcc); _median_sort(Jnc, Jpn); _median_sort(Jbc, Jpn); _median_sort(Jbc, Jnc); _median_sort(Jba, Jna); _median_sort(Jcn, Jna); _median_sort(Jcn, Jba); _median_sort(Jpa, Jaa); _median_sort(Jnn, Jaa); _median_sort(Jnn, Jpa); _median_sort(Jan, Jca); _median_sort(Jnp, Jcn); _median_sort(Jap, Jnn); _median_sort(Jbb, Jnn); _median_sort(Jbb, Jap); _median_sort(Jbc, Jan); _median_sort(Jpb, Jan); _median_sort(Jpb, Jbc); _median_sort(Jpc, Jba); _median_sort(Jcb, Jba); _median_sort(Jcb, Jpc); _median_sort(Jcc, Jpa); _median_sort(Jnb, Jpa); _median_sort(Jnb, Jcc); _median_sort(Jnc, Jca); _median_sort(Jab, Jca); _median_sort(Jab, Jnc); _median_sort(Jac, Jna); _median_sort(Jbp, Jna); _median_sort(Jbp, Jac); _median_sort(Jbn, Jaa); _median_sort(Jpp, Jaa); _median_sort(Jpp, Jbn); _median_sort(Jcp, Jpn); _median_sort(Jcp, Jan); _median_sort(Jnc, Jpa); _median_sort(Jbn, Jna); _median_sort(Jcp, Jnc); _median_sort(Jcp, Jbn); _median_sort(Jpb, Jap); _median_sort(Jnb, Jpc); _median_sort(Jbp, Jcn); _median_sort(Jpc, Jcn); _median_sort(Jap, Jcn); _median_sort(Jab, Jbc); _median_sort(Jpp, Jcc); _median_sort(Jcp, Jac); _median_sort(Jab, Jpp); _median_sort(Jab, Jcp); _median_sort(Jcc, Jac); _median_sort(Jbc, Jac); _median_sort(Jpp, Jcp); _median_sort(Jbc, Jcc); _median_sort(Jpp, Jbc); _median_sort(Jpp, Jcn); _median_sort(Jcc, Jcn); _median_sort(Jcp, Jcn); _median_sort(Jcp, Jbc); _median_sort(Jcc, Jnn); _median_sort(Jcp, Jcc); _median_sort(Jbc, Jnn); _median_sort(Jcc, Jba); _median_sort(Jbc, Jba); _median_sort(Jbc, Jcc); res(x,y,0,k) = Jcc; } } break; default: { CImg vois; cimg_forXYV(*this,x,y,k) { vois = get_crop(x-hl,y-hl,0,k,x+hr,y+hr,0,k); res(x,y,0,k) = vois.median(); } } break; } } return res; } //! Apply a median filter CImg& blur_median(const unsigned int n=3) { return get_blur_median(n).swap(*this); } //! Sharpen image using anisotropic shock filters CImg& sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) { if (is_empty()) return *this; const bool threed = (depth>1); const float nedge = 0.5f*edge; typedef typename cimg::largest::type ftype; CImg val, vec, veloc(width,height,depth,dim); if (threed) { CImg G = (alpha>0?get_blur(alpha).get_structure_tensorXYZ():get_structure_tensorXYZ()); if (sigma>0) G.blur(sigma); CImg_3x3x3(I,float); cimg_forXYZ(G,x,y,z) { G.get_tensor_at(x,y,z).symmetric_eigen(val,vec); G(x,y,z,0) = vec(0,0); G(x,y,z,1) = vec(0,1); G(x,y,z,2) = vec(0,2); G(x,y,z,3) = 1.0f-(float)std::pow((float)(1+val[0]+val[1]+val[2]),-nedge); } cimg_forV(*this,k) cimg_for3x3x3(*this,x,y,z,k,I) { const float u = G(x,y,z,0), v = G(x,y,z,1), w = G(x,y,z,2), amp = G(x,y,z,3), ixx = Incc+Ipcc-2*Iccc, ixy = 0.25f*(Innc+Ippc-Inpc-Ipnc), ixz = 0.25f*(Incn+Ipcp-Incp-Ipcn), iyy = Icnc+Icpc-2*Iccc, iyz = 0.25f*(Icnn+Icpp-Icnp-Icpn), izz = Iccn+Iccp-2*Iccc, ixf = Incc-Iccc, ixb = Iccc-Ipcc, iyf = Icnc-Iccc, iyb = Iccc-Icpc, izf = Iccn-Iccc, izb = Iccc-Iccp, itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz, it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb); veloc(x,y,z,k) = -amp*cimg::sign(itt)*cimg::abs(it); } } else { CImg G = (alpha>0?get_blur(alpha).get_structure_tensorXY():get_structure_tensorXY()); if (sigma>0) G.blur(sigma); CImg_3x3(I,float); cimg_forXY(G,x,y) { G.get_tensor_at(x,y).symmetric_eigen(val,vec); G(x,y,0) = vec(0,0); G(x,y,1) = vec(0,1); G(x,y,2) = 1.0f-(float)std::pow((float)(1+val[0]+val[1]),-nedge); } cimg_forV(*this,k) cimg_for3x3(*this,x,y,0,k,I) { const float u = G(x,y,0), v = G(x,y,1), amp = G(x,y,2), ixx = Inc+Ipc-2*Icc, ixy = 0.25f*(Inn+Ipp-Inp-Ipn), iyy = Icn+Icp-2*Icc, ixf = Inc-Icc, ixb = Icc-Ipc, iyf = Icn-Icc, iyb = Icc-Icp, itt = u*u*ixx + v*v*iyy + 2*u*v*ixy, it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb); veloc(x,y,k) = -amp*cimg::sign(itt)*cimg::abs(it); } } const CImgStats stats(veloc); const float vmax = (float)cimg::max(cimg::abs(stats.min),cimg::abs(stats.max)); if (vmax!=0) { veloc*=amplitude/vmax; (*this)+=veloc; } return *this; } CImg get_sharpen(const float amplitude=50.0f, const float edge=1.0f, const float alpha=0.0f, const float sigma=0.0f) const { return (+*this).sharpen(amplitude,edge,alpha,sigma); } //! Estimate displacement field between instance image and given reference image. CImg::type> get_displacement_field(const CImg& reference, const float smooth=0.1f, const float precision=1e-6f, const unsigned int nb_scale=0, const unsigned int itermax=10000) const { typedef typename cimg::largest::type ftype; if (is_empty() || !reference) return *this; if (!is_sameXYZ(reference)) throw CImgArgumentException("CImg<%s>::get_displacement_field() : Instance image (%u,%u,%u,%u,%p) and reference image (%u,%u,%u,%u,%p) " "must have same dimensions", pixel_type(),width,height,depth,dim,data, reference.width,reference.height,reference.depth,reference.dim,reference.data); const bool threed = depth>1; CImg u(width,height,depth,threed?3:2,0); const unsigned int nbs = nb_scale>0?nb_scale:(unsigned int)(2*std::log((double)(cimg::max(width,height,depth)))); for (int scale=nbs-1; scale>=0; scale--) { const float fact = (float)std::pow(1.5f,-(float)scale); const unsigned int tnw = (unsigned int)(width*fact), nw = tnw?tnw:1, tnh = (unsigned int)(height*fact), nh = tnh?tnh:1, tnd = (unsigned int)(depth*fact), nd = tnd?tnd:1; CImg I1 = get_resize(nw,nh,nd,1,3), I2 = reference.get_resize(nw,nh,nd,1,3); I1.norm_pointwise(1); I2.norm_pointwise(2); const CImgStats st1(I1,false), st2(I2,false); const float M = cimg::max(cimg::abs(st1.min),cimg::abs(st1.max),cimg::abs(st2.min),cimg::abs(st2.max)); I1/=M; I2/=M; u*=1.5; u.resize(nw,nh,nd,threed?3:2,3); float dt = 100, E = cimg::type::max(), nprecision = nw*nh*nd*precision; const CImgList dI = threed?I2.get_gradientXYZ():I2.get_gradientXY(); for (unsigned int iter=0; iter& reference, const float smooth=0.1f, const float precision=1e-6f, const unsigned int nb_scale=0, const unsigned int itermax=10000) { return assign(get_displacement_field(reference,smooth,precision,nb_scale,itermax)); } //@} //----------------------------- // //! \name Matrix and Vectors //@{ //----------------------------- //! Return a vector with specified coefficients static CImg vector(const T& a1) { return CImg(1,1).fill(a1); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2) { return CImg(1,2).fill(a1,a2); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3) { return CImg(1,3).fill(a1,a2,a3); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4) { return CImg(1,4).fill(a1,a2,a3,a4); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5) { return CImg(1,5).fill(a1,a2,a3,a4,a5); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) { return CImg(1,6).fill(a1,a2,a3,a4,a5,a6); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7) { return CImg(1,7).fill(a1,a2,a3,a4,a5,a6,a7); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8) { return CImg(1,8).fill(a1,a2,a3,a4,a5,a6,a7,a8); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8,const T& a9) { return CImg(1,9).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8, const T& a9,const T& a10) { return CImg(1,10).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8, const T& a9,const T& a10, const T& a11) { return CImg(1,11).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8, const T& a9,const T& a10, const T& a11, const T& a12) { return CImg(1,12).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); } //! Return a vector with specified coefficients static CImg vector(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8, const T& a9,const T& a10, const T& a11, const T& a12, const T& a13) { return CImg(1,13).fill(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13); } //! Return a 1x1 square matrix with specified coefficients static CImg matrix(const T& a1) { return vector(a1); } //! Return a 2x2 square matrix with specified coefficients static CImg matrix(const T& a1,const T& a2, const T& a3,const T& a4) { return CImg(2,2).fill(a1,a2, a3,a4); } //! Return a 3x3 square matrix with specified coefficients static CImg matrix(const T& a1,const T& a2,const T& a3, const T& a4,const T& a5,const T& a6, const T& a7,const T& a8,const T& a9) { return CImg(3,3).fill(a1,a2,a3, a4,a5,a6, a7,a8,a9); } //! Return a 4x4 square matrix with specified coefficients static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4, const T& a5,const T& a6,const T& a7,const T& a8, const T& a9,const T& a10,const T& a11,const T& a12, const T& a13,const T& a14,const T& a15,const T& a16) { return CImg(4,4).fill(a1,a2,a3,a4, a5,a6,a7,a8, a9,a10,a11,a12, a13,a14,a15,a16); } //! Return a 5x5 square matrix with specified coefficients static CImg matrix(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5, const T& a6,const T& a7,const T& a8,const T& a9,const T& a10, const T& a11,const T& a12,const T& a13,const T& a14,const T& a15, const T& a16,const T& a17,const T& a18,const T& a19,const T& a20, const T& a21,const T& a22,const T& a23,const T& a24,const T& a25) { return CImg(5,5).fill(a1,a2,a3,a4,a5, a6,a7,a8,a9,a10, a11,a12,a13,a14,a15, a16,a17,a18,a19,a20, a21,a22,a23,a24,a25); } //! In-place version of get_matrix(). CImg& matrix() { const unsigned int siz = size(); switch (siz) { case 1: break; case 4: width = height = 2; break; case 9: width = height = 3; break; case 16: width = height = 4; break; case 25: width = height = 5; break; case 36: width = height = 6; break; case 49: width = height = 7; break; case 64: width = height = 8; break; case 81: width = height = 9; break; case 100: width = height = 10; break; default: { unsigned int i=11, i2=i*i; while (i2::matrix() : Image size = %u is not a square number",pixel_type(),siz); } break; } return *this; } //! Realign pixel values of the instance image as a square matrix CImg get_matrix() const { return (+*this).matrix(); } //! Return a 1x1 symmetric matrix with specified coefficients static CImg tensor(const T& a1) { return matrix(a1); } //! Return a 2x2 symmetric matrix tensor with specified coefficients static CImg tensor(const T& a1,const T& a2,const T& a3) { return matrix(a1,a2, a2,a3); } //! Return a 3x3 symmetric matrix with specified coefficients static CImg tensor(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5,const T& a6) { return matrix(a1,a2,a3, a2,a4,a5, a3,a5,a6); } CImg get_tensor() const { CImg res; const unsigned int siz = size(); switch (siz) { case 1: break; case 3: res.assign(2,2); res(0,0) = (*this)(0); res(1,0) = res(0,1) = (*this)(1); res(1,1) = (*this)(2); break; case 6: res.assign(3,3); res(0,0) = (*this)(0); res(1,0) = res(0,1) = (*this)(1); res(2,0) = res(0,2) = (*this)(2); res(1,1) = (*this)(3); res(2,1) = res(1,2) = (*this)(4); res(2,2) = (*this)(5); break; default: throw CImgInstanceException("CImg<%s>::tensor() : Wrong vector dimension = %u in instance image.", pixel_type(), dim); break; } return res; } //! In-place version of get_tensor(). CImg& tensor() { return get_tensor().swap(*this); } //! Return a 1x1 diagonal matrix with specified coefficients static CImg diagonal(const T& a1) { return matrix(a1); } //! Return a 2x2 diagonal matrix with specified coefficients static CImg diagonal(const T& a1,const T& a2) { return matrix(a1,0, 0,a2); } //! Return a 3x3 diagonal matrix with specified coefficients static CImg diagonal(const T& a1,const T& a2,const T& a3) { return matrix(a1,0,0, 0,a2,0, 0,0,a3); } //! Return a 4x4 diagonal matrix with specified coefficients static CImg diagonal(const T& a1,const T& a2,const T& a3,const T& a4) { return matrix(a1,0,0,0, 0,a2,0,0, 0,0,a3,0, 0,0,0,a4); } //! Return a 5x5 diagonal matrix with specified coefficients static CImg diagonal(const T& a1,const T& a2,const T& a3,const T& a4,const T& a5) { return matrix(a1,0,0,0,0, 0,a2,0,0,0, 0,0,a3,0,0, 0,0,0,a4,0, 0,0,0,0,a5); } //! Unroll all images values into specified axis. CImg& unroll(const char axe='x') { const unsigned int siz = size(); if (siz) switch (axe) { case 'x': width = siz; height=depth=dim=1; break; case 'y': height = siz; width=depth=dim=1; break; case 'z': depth = siz; width=height=dim=1; break; case 'v': dim = siz; width=height=depth=1; break; default: throw CImgArgumentException("CImg<%s>::unroll() : Given axe is '%c' which is not 'x','y','z' or 'v'", pixel_type(),axe); } return *this; } CImg get_unroll(const char axe='x') const { return (+*this).unroll(axe); } CImg& vector() { return unroll('y'); } CImg get_vector() const { return get_unroll('y'); } //! Get a diagonal matrix, whose diagonal coefficients are the coefficients of the input image CImg get_diagonal() const { if (is_empty()) return CImg(); CImg res(size(),size(),1,1,0); cimg_foroff(*this,off) res(off,off)=(*this)(off); return res; } //! Replace a vector by a diagonal matrix containing the original vector coefficients. CImg& diagonal() { return get_diagonal().swap(*this); } //! Return a NxN identity matrix static CImg identity_matrix(const unsigned int N) { CImg res(N,N,1,1,0); cimg_forX(res,x) res(x,x)=1; return res; } CImg& identity_matrix() { return identity_matrix(cimg::max(width,height)).swap(*this); } CImg get_identity_matrix() const { return identity_matrix(cimg::max(width,height)); } //! Return a N-numbered sequence vector from \p a0 to \p a1 CImg& sequence(const T& a0, const T& a1) { if (!is_empty()) { const unsigned int siz = size()-1; const float delta = (float)((float)a1-a0); T* ptr = data; cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz); } return *this; } CImg get_sequence(const T& a0, const T& a1) const { return (+*this).sequence(a0,a1); } static CImg sequence(const unsigned int N, const T& a0, const T& a1) { if (N) return CImg(1,N).sequence(a0,a1); return CImg(); } //! Return a 3x3 rotation matrix along the (x,y,z)-axis with an angle w. static CImg rotation_matrix(const float x, const float y, const float z, const float w, const bool quaternion_data=false) { float X,Y,Z,W; if (!quaternion_data) { const float norm = (float)std::sqrt(x*x + y*y + z*z), nx = norm>0?x/norm:0, ny = norm>0?y/norm:0, nz = norm>0?z/norm:1, nw = norm>0?w:0, sina = (float)std::sin(nw/2), cosa = (float)std::cos(nw/2); X = nx*sina; Y = ny*sina; Z = nz*sina; W = cosa; } else { const float norm = (float)std::sqrt(x*x + y*y + z*z + w*w); if (norm>0) { X=x/norm; Y=y/norm; Z=z/norm; W=w/norm; } else { X=Y=Z=0; W=1; } } 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; return CImg::matrix((T)(1-2*(yy+zz)), (T)(2*(xy+zw)), (T)(2*(xz-yw)), (T)(2*(xy-zw)), (T)(1-2*(xx+zz)), (T)(2*(yz+xw)), (T)(2*(xz+yw)), (T)(2*(yz-xw)), (T)(1-2*(xx+yy))); } //! Return a new image corresponding to the vector located at (\p x,\p y,\p z) of the current vector-valued image. CImg get_vector_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const { CImg dest(1,dim); cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k); return dest; } //! 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. CImg get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const { const int n = (int)std::sqrt((double)dim); CImg dest(n,n); cimg_forV(*this,k) dest[k]=(*this)(x,y,z,k); return dest; } //! 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. CImg get_tensor_at(const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) const { if (dim==6) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2), (*this)(x,y,z,3),(*this)(x,y,z,4),(*this)(x,y,z,5)); if (dim==3) return tensor((*this)(x,y,z,0),(*this)(x,y,z,1),(*this)(x,y,z,2)); return tensor((*this)(x,y,z,0)); } //! 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. CImg& set_vector_at(const CImg& vec,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { return draw_point(x,y,z,vec.data,1); } //! 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. CImg& set_matrix_at(const CImg& mat,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { return set_vector_at(mat,x,y,z); } //! 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. CImg& set_tensor_at(const CImg& ten,const unsigned int x=0,const unsigned int y=0,const unsigned int z=0) { if (ten.height==2) { (*this)(x,y,z,0)=ten[0]; (*this)(x,y,z,1)=ten[1]; (*this)(x,y,z,2)=ten[3]; } else { (*this)(x,y,z,0)=ten[0]; (*this)(x,y,z,1)=ten[1]; (*this)(x,y,z,2)=ten[2]; (*this)(x,y,z,3)=ten[4]; (*this)(x,y,z,4)=ten[5]; (*this)(x,y,z,5)=ten[8]; } return *this; } //! Return the transpose version of the current matrix. CImg get_transpose() const { return get_permute_axes("yxzv"); } //! Replace the current matrix by its transpose. CImg& transpose() { if (width==1) { width=height; height=1; return *this; } if (height==1) { height=width; width=1; return *this; } if (width==height) { cimg_forYZV(*this,y,z,v) for (int x=y; x<(int)width; x++) cimg::swap((*this)(x,y,z,v),(*this)(y,x,z,v)); return *this; } return get_transpose().swap(*this); } //! Inverse the current matrix. CImg& inverse(const bool use_LU=true) { if (!is_empty()) { if (width!=height || depth!=1 || dim!=1) throw CImgInstanceException("CImg<%s>::inverse() : Instance matrix (%u,%u,%u,%u,%p) is not square.", pixel_type(),width,height,depth,dim,data); const double dete = width>3?-1.0:det(); if (dete!=0.0 && width==2) { const double a = data[0], c = data[1], b = data[2], d = data[3]; data[0] = (T)(d/dete); data[1] = (T)(-c/dete); data[2] = (T)(-b/dete), data[3] = (T)(a/dete); } else if (dete!=0.0 && width==3) { const double a = data[0], d = data[1], g = data[2], b = data[3], e = data[4], h = data[5], c = data[6], f = data[7], i = data[8]; data[0] = (T)((i*e-f*h)/dete), data[1] = (T)((g*f-i*d)/dete), data[2] = (T)((d*h-g*e)/dete); data[3] = (T)((h*c-i*b)/dete), data[4] = (T)((i*a-c*g)/dete), data[5] = (T)((g*b-a*h)/dete); data[6] = (T)((b*f-e*c)/dete), data[7] = (T)((d*c-a*f)/dete), data[8] = (T)((a*e-d*b)/dete); } else { typedef typename cimg::largest::type ftype; if (use_LU) { // LU-based inverse computation CImg A(*this), indx, col(1,width); bool d; A._LU(indx,d); cimg_forX(*this,j) { col.fill(0); col(j) = 1; col._solve(A,indx); cimg_forX(*this,i) (*this)(j,i) = (T)col(i); } } else { // SVD-based inverse computation CImg U(width,width), S(1,width), V(width,width); SVD(U,S,V,false); U.transpose(); cimg_forY(S,k) if (S[k]!=0) S[k]=1/S[k]; S.diagonal(); *this = V*S*U; } } } return *this; } //! Return the inverse of the current matrix. CImg::type> get_inverse(const bool use_LU=true) const { typedef typename cimg::largest::type restype; return CImg(*this,false).inverse(use_LU); } //! Return the pseudo-inverse (Moore-Penrose) of the matrix CImg::type> get_pseudoinverse() const { typedef typename cimg::largest::type restype; CImg At = get_transpose(), At2(At); return (((At*=*this).inverse())*=At2); } //! Replace the matrix by its pseudo-inverse CImg& pseudoinverse() { typedef typename cimg::largest::type restype; CImg At = get_transpose(), At2(At); ((At*=*this).inverse())*=At2; return ((*this)=At); } //! Return the trace of the current matrix. double trace() const { if (is_empty()) throw CImgInstanceException("CImg<%s>::trace() : Instance matrix (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); double res=0; cimg_forX(*this,k) res+=(*this)(k,k); return res; } //! Return the kth smallest element of the image // (Adapted from the numerical recipies for CImg) const T kth_smallest(const unsigned int k) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::kth_smallest() : Instance image (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); CImg arr(*this); unsigned long l=0,ir=size()-1; for (;;) { if (ir<=l+1) { if (ir==l+1 && arr[ir]>1; cimg::swap(arr[mid],arr[l+1]); if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); if (arr[l+1]>arr[ir]) cimg::swap(arr[l+1],arr[ir]); if (arr[l]>arr[l+1]) cimg::swap(arr[l],arr[l+1]); unsigned long i = l+1, j = ir; const T pivot = arr[l+1]; for (;;) { do i++; while (arr[i]pivot); if (j=k) ir=j-1; if (j<=k) l=i; } } return 0; } //! Return the median of the image const T median() const { const unsigned int s = size(); const T res = kth_smallest(s>>1); return (s%2)?res:((res+kth_smallest((s>>1)-1))/2); } //! Return the dot product of the current vector/matrix with the vector/matrix \p img. double dot(const CImg& img) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::dot() : Instance object (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); if (!img) throw CImgArgumentException("CImg<%s>::trace() : Specified argument (%u,%u,%u,%u,%p) is empty.", pixel_type(),img.width,img.height,img.depth,img.dim,img.data); const unsigned long nb = cimg::min(size(),img.size()); double res=0; for (unsigned long off=0; off::cross() : Arguments (%u,%u,%u,%u,%p) and (%u,%u,%u,%u,%p) must be both 3d vectors.", pixel_type(),width,height,depth,dim,data,img.width,img.height,img.depth,img.dim,img.data); const T x = (*this)[0], y = (*this)[1], z = (*this)[2]; (*this)[0] = y*img[2]-z*img[1]; (*this)[1] = z*img[0]-x*img[2]; (*this)[2] = x*img[1]-y*img[0]; return *this; } //! Return the cross product between two 3d vectors CImg get_cross(const CImg& img) const { return (+*this).cross(img); } //! Return the determinant of the current matrix. double det() const { if (is_empty() || width!=height || depth!=1 || dim!=1) throw CImgInstanceException("CImg<%s>::det() : Instance matrix (%u,%u,%u,%u,%p) is not square or is empty.", pixel_type(),width,height,depth,dim,data); switch (width) { case 1: return (*this)(0,0); case 2: return (*this)(0,0)*(*this)(1,1)-(*this)(0,1)*(*this)(1,0); case 3: { const double a = data[0], d = data[1], g = data[2], b = data[3], e = data[4], h = data[5], c = data[6], f = data[7], i = data[8]; return i*a*e-a*h*f-i*b*d+b*g*f+c*d*h-c*g*e; } default: { typedef typename cimg::largest::type ftype; CImg lu(*this); CImg indx; bool d; lu._LU(indx,d); double res = d?1.0:-1.0; cimg_forX(lu,i) res*=lu(i,i); return res; } } return 0; } //! Return the norm of the current vector/matrix. \p ntype = norm type (0=L2, 1=L1, -1=Linf). double norm(const int ntype=2) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::norm() : Instance object (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); double res = 0; switch (ntype) { case -1: { cimg_foroff(*this,off) { const double tmp = cimg::abs((double)data[off]); if (tmp>res) res = tmp; } return res; } break; case 1 : { cimg_foroff(*this,off) res+=cimg::abs((double)data[off]); return res; } break; default: { return std::sqrt(dot(*this)); } } return 0; } //! Return the sum of all the pixel values in an image. double sum() const { if (is_empty()) throw CImgInstanceException("CImg<%s>::sum() : Instance object (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); double res=0; cimg_for(*this,ptr,T) res+=*ptr; return res; } //! Compute the SVD of a general matrix. template const CImg& SVD(CImg& U, CImg& S, CImg& V, const bool sorting=true, const unsigned int max_iter=40) const { if (is_empty()) { U.assign(); S.assign(); V.assign(); } else { U = *this; if (S.size() rv1(width); t anorm=0,c,f,g=0,h,s,scale=0; int l=0, nm=0; cimg_forX(U,i) { l = i+1; rv1[i] = scale*g; g = s = scale = 0; if (i=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i)=f-g; for (int j=l; j=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; { for (int k=l; k=0; i--) { if (i=0; i--) { l = i+1; g = S[i]; for (int j=l; j=0; k--) { for (unsigned int its=0; its=1; l--) { nm = l-1; if ((cimg::abs(rv1[l])+anorm)==anorm) { flag = false; break; } if ((cimg::abs(S[nm])+anorm)==anorm) break; } if (flag) { c = 0; s = 1; for (int i=l; i<=k; i++) { f = s*rv1[i]; rv1[i] = c*rv1[i]; if ((cimg::abs(f)+anorm)==anorm) break; g = S[i]; h = (t)cimg::pythagore(f,g); S[i] = h; h = 1/h; c = g*h; s = -f*h; 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; } } } const t& z = S[k]; if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; } nm = k-1; t x = S[l], y = S[nm]; g = rv1[nm]; h = rv1[k]; f = ((y-z)*(y+z)+(g-h)*(g+h))/(2*h*y); g = (t)cimg::pythagore(f,1.0); f = ((x-z)*(x+z)+h*((y/(f+ (f>=0?g:-g)))-h))/x; c = s = 1; for (int j=l; j<=nm; j++) { const int i = j+1; g = rv1[i]; h = s*g; g = c*g; t y = S[i]; t z = (t)cimg::pythagore(f,h); rv1[j] = z; c = f/z; s = h/z; f = x*c+g*s; g = g*c-x*s; h = y*s; y*=c; 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; } z = (t)cimg::pythagore(f,h); S[j] = z; if (z) { z = 1/z; c = f*z; s = h*z; } f = c*g+s*y; x = c*y-s*g; { 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; }} } rv1[l] = 0; rv1[k]=f; S[k]=x; } } if (sorting) { CImg permutations(width); CImg tmp(width); S.sort(permutations,false); cimg_forY(U,k) { cimg_forX(permutations,x) tmp(x) = U(permutations(x),k); std::memcpy(U.ptr(0,k),tmp.data,sizeof(t)*width); } { cimg_forY(V,k) { cimg_forX(permutations,x) tmp(x) = V(permutations(x),k); std::memcpy(V.ptr(0,k),tmp.data,sizeof(t)*width); }} } } return *this; } //! Compute the SVD of a general matrix. template const CImg& SVD(CImgList& USV) const { if (USV.size<3) USV.assign(3); return SVD(USV[0],USV[1],USV[2]); } //! Compute the SVD of a general matrix. CImgList::type> get_SVD(const bool sorting=true) const { typedef typename cimg::largest::type restype; CImgList res(3); SVD(res[0],res[1],res[2],sorting); return res; } // INNER ROUTINE : Compute the LU decomposition of a permuted matrix (c.f. numerical recipies) template CImg& _LU(CImg& indx, bool& d) { typedef typename cimg::largest::type ftype; const int N = dimx(); int imax=0; CImg vv(N); indx.assign(N); d=true; cimg_forX(*this,i) { ftype vmax=0.0; cimg_forX(*this,j) { const ftype tmp = cimg::abs((*this)(j,i)); if (tmp>vmax) vmax = tmp; } if (vmax==0) return fill(0); vv[i] = 1/vmax; } cimg_forX(*this,j) { for (int i=0; i=vmax) { vmax=tmp; imax=i; } }} if (j!=imax) { cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j)); d =!d; vv[imax] = vv[j]; } indx[j] = (t)imax; if ((*this)(j,j)==0) (*this)(j,j)=(T)1e-20; if (j CImg& _solve(const CImg& A, const CImg& indx) { typedef typename cimg::largest::type ftype; const int N = size(); int ii=-1; ftype sum; for (int i=0; i=0) for (int j=ii; j<=i-1; j++) sum-=A(j,i)*(*this)(j); else if (sum!=0) ii=i; (*this)(i) = (T)sum; } { for (int i=N-1; i>=0; i--) { sum = (*this)(i); for (int j=i+1; j::solve() : Instance matrix size is (%u,%u,%u,%u) while " "size of given matrix A is (%u,%u,%u,%u).", pixel_type(),width,height,depth,dim,A.width,A.height,A.depth,A.dim); if (A.width==A.height) { CImg lu(A); CImg indx; bool d; lu._LU(indx,d); _solve(lu,indx); } else assign(A.get_pseudoinverse()*(*this)); return *this; } //! Solve a linear system AX=B where B=*this. CImg::type> get_solve(const CImg& A) const { typedef typename cimg::largest::type restype; return CImg(*this,false).solve(A); } //! Compute the eigenvalues and eigenvectors of a matrix. template const CImg& eigen(CImg& val, CImg &vec) const { if (is_empty()) { val.assign(); vec.assign(); } else { if (width!=height || depth>1 || dim>1) throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); if (val.size()::eigen() : Complex eigenvalues",pixel_type()); f = std::sqrt(f); const double l1 = 0.5*(e-f), l2 = 0.5*(e+f); const double theta1 = std::atan2(l2-a,b), theta2 = std::atan2(l1-a,b); val[0]=(t)l2; val[1]=(t)l1; vec(0,0) = (t)std::cos(theta1); vec(0,1) = (t)std::sin(theta1); vec(1,0) = (t)std::cos(theta2); vec(1,1) = (t)std::sin(theta2); } break; default: throw CImgInstanceException("CImg<%s>::eigen() : Eigenvalues computation of general matrices is limited" "to 2x2 matrices (given is %ux%u)", pixel_type(),width,height); } } return *this; } //! Return the eigenvalues and eigenvectors of a matrix. CImgList::type> get_eigen() const { typedef typename cimg::largest::type restype; CImgList res(2); eigen(res[0],res[1]); return res; } //! Compute the eigenvalues and eigenvectors of a matrix. template const CImg& eigen(CImgList& eig) const { if (eig.size<2) eig.assign(2); eigen(eig[0],eig[1]); return *this; } //! Compute the eigenvalues and eigenvectors of a symmetric matrix. template const CImg& symmetric_eigen(CImg& val, CImg& vec) const { if (is_empty()) { val.assign(); vec.assign(); } else { if (width!=height || depth>1 || dim>1) throw CImgInstanceException("CImg<%s>::eigen() : Instance object (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); if (val.size() V(width,width); SVD(vec,val,V,false); cimg_forX(vec,x) { // check for negative eigenvalues t scal=0; cimg_forY(vec,y) scal+=vec(x,y)*V(x,y); if (scal<0) val[x]=-val[x]; } CImg permutations(width); // sort eigenvalues in decreasing order CImg tmp(width); val.sort(permutations,false); cimg_forY(vec,k) { cimg_forX(permutations,x) tmp(x) = vec(permutations(x),k); std::memcpy(vec.ptr(0,k),tmp.data,sizeof(t)*width); } } return *this; } //! Compute the eigenvalues and eigenvectors of a symmetric matrix. CImgList::type> get_symmetric_eigen() const { typedef typename cimg::largest::type restype; CImgList res(2); symmetric_eigen(res[0],res[1]); return res; } //! Compute the eigenvalues and eigenvectors of a symmetric matrix. template const CImg& symmetric_eigen(CImgList& eig) const { if (eig.size<2) eig.assign(2); symmetric_eigen(eig[0],eig[1]); return *this; } template CImg& _quicksort(const int min,const int max,CImg& permutations,const bool increasing) { if (min(*this)[mid]) { cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } if ((*this)[mid]>(*this)[max]) { cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } if ((*this)[min]>(*this)[mid]) { cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } } else { if ((*this)[min]<(*this)[mid]) { cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } if ((*this)[mid]<(*this)[max]) { cimg::swap((*this)[max],(*this)[mid]); cimg::swap(permutations[max],permutations[mid]); } if ((*this)[min]<(*this)[mid]) { cimg::swap((*this)[min],(*this)[mid]); cimg::swap(permutations[min],permutations[mid]); } } if (max-min>=3) { const T pivot = (*this)[mid]; int i = min, j = max; if (increasing) { do { while ((*this)[i]pivot) j--; if (i<=j) { cimg::swap((*this)[i],(*this)[j]); cimg::swap(permutations[i++],permutations[j--]); } } while (i<=j); } else { do { while ((*this)[i]>pivot) i++; while ((*this)[j] CImg& sort(CImg& permutations,const bool increasing=true) { if (is_empty()) permutations.assign(); else { if (permutations.size()!=size()) permutations.assign(size()); cimg_foroff(permutations,off) permutations[off] = (t)off; _quicksort(0,size()-1,permutations,increasing); } return *this; } //! Sort values of a vector. CImg& sort(const bool increasing=true) { CImg foo; return sort(foo,increasing); } //! Get a sorted version a of vector, with permutations. template CImg get_sort(CImg& permutations,const bool increasing=true) { return (+*this).sort(permutations,increasing); } //! Get a sorted version of a vector. CImg get_sort(const bool increasing=true) { return (+*this).sort(increasing); } //! Get a permutation of the pixels template CImg get_permute(const CImg& permutation) const { if (permutation.size()!=size()) throw CImgArgumentException("CImg<%s>::permute() : Instance image (%u,%u,%u,%u,%p) and permutation (%u,%u,%u,%u,%p)" "have different sizes.",pixel_type(), width,height,depth,dim,data, permutation.width,permutation.height,permutation.depth,permutation.dim,permutation.data); CImg res(width,height,depth,dim); const t *p = permutation.ptr(permutation.size()); cimg_for(res,ptr,T) *ptr = (*this)[*(--p)]; return res; } //! In-place version of the previous function template CImg& permute(const CImg& permutation) { return get_permute(permutation).swap(*this); } //@} //------------------- // //! \name Display //@{ //------------------- //! Display an image into a CImgDisplay window. const CImg& display(CImgDisplay& disp) const { disp.display(*this); return *this; } //! Display an image in a window with a title \p title, and wait a 'is_closed' or 'keyboard' event.\n //! Parameters \p min_size and \p max_size set the minimum and maximum dimensions of the display window. //! If negative, they corresponds to a percentage of the original image size. const CImg& display(const char* title, const int min_size=128, const int max_size=1024) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::display() : Instance image (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); CImgDisplay *disp; unsigned int w = width+(depth>1?depth:0), h = height+(depth>1?depth:0), XYZ[3]; print(title); const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100; if (dmin=0?max_size:(-max_size)*dmax/100; if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); } disp = new CImgDisplay(w,h,title,3,3); XYZ[0] = width/2; XYZ[1] = height/2; XYZ[2] = depth/2; while (!disp->is_closed && !disp->key) feature_selection(0,1,*disp,XYZ); delete disp; return *this; } //! Display an image in a window, with a default title. See also \see display() for details on parameters. const CImg& display(const int min_size=128, const int max_size=1024) const { char title[256]={0}; std::sprintf(title,"CImg<%s>",pixel_type()); return display(title,min_size,max_size); } //! High-level interface to select features from images const CImg& feature_selection(int* const selection, const int feature_type, CImgDisplay &disp, unsigned int *const XYZ=0,const unsigned char *const color=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::feature_selection() : Instance image (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data); const unsigned int old_events = disp.events, old_normalization = disp.normalization, hatch = 0x55555555; bool old_is_resized = disp.is_resized; disp.events = 3; disp.normalization = 0; disp.show().key = 0; unsigned char fgcolor[3] = { 255,255,105 }, bgcolor[3] = { 0,0,0 }; if (color) std::memcpy(fgcolor,color,sizeof(unsigned char)*cimg::min(3,dimv())); int area = 0, clicked_area = 0, phase = 0, X0 = (int)((XYZ?XYZ[0]:width/2)%width), Y0 = (int)((XYZ?XYZ[1]:height/2)%height), Z0 = (int)((XYZ?XYZ[2]:depth/2)%depth), X1 =-1, Y1 = -1, Z1 = -1, X = -1, Y = -1, Z = -1, oX = X, oY = Y, oZ = Z; unsigned int old_button = 0, key = 0; bool feature_selected = false, text_down = false; CImg visu, visu0; char text[1024] = { 0 }; while (!key && !disp.is_closed && !feature_selected) { // Handle mouse motion and selection oX = X; oY = Y; oZ = Z; int mx = disp.mouse_x, my = disp.mouse_y; const int mX = mx*(width+(depth>1?depth:0))/disp.width, mY = my*(height+(depth>1?depth:0))/disp.height; area = 0; if (mX=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; } if (mX>=dimx() && mY=2) { switch (clicked_area) { case 1: Z1 = Z; break; case 2: Y1 = Y; break; case 3: X1 = X; break; } } if (disp.button&2) { if (phase) { X1 = X; Y1 = Y; Z1 = Z; } else { X0 = X; Y0 = Y; Z0 = Z; } } if (disp.button&4) { oX = X = X0; oY = Y = Y0; oZ = Z = Z0; phase = 0; visu.assign(); } if (disp.wheel) { switch (area) { case 1: if (phase) Z = (Z1+=disp.wheel); else Z = (Z0+=disp.wheel); break; case 2: if (phase) Y = (Y1+=disp.wheel); else Y = (Y0+=disp.wheel); break; case 3: if (phase) X = (X1+=disp.wheel); else X = (X0+=disp.wheel); break; default: break; } disp.wheel = 0; } if ((disp.button&1)!=old_button) { switch (phase++) { case 0: X0 = X1 = X; Y0 = Y1 = Y; Z0 = Z1 = Z; clicked_area = area; break; case 1: X1 = X; Y1 = Y; Z1 = Z; break; default: break; } old_button = disp.button&1; } if (depth>1 && (X!=oX || Y!=oY || Z!=oZ)) visu0.assign(); } if (phase) { if (!feature_type) feature_selected = phase?true:false; else { if (depth>1) feature_selected = (phase==3)?true:false; else feature_selected = (phase==2)?true:false; } } if (X0<0) X0 = 0; if (X0>=(int)width) X0 = (int)width-1; if (Y0<0) Y0 = 0; if (Y0>=(int)height) Y0 = (int)height-1; if (Z0<0) Z0 = 0; if (Z0>=(int)depth) Z0 = (int)depth-1; if (X1<1) X1 = 0; if (X1>=(int)width) X1 = (int)width-1; if (Y1<0) Y1 = 0; if (Y1>=(int)height) Y1 = (int)height-1; if (Z1<0) Z1 = 0; if (Z1>=(int)depth) Z1 = (int)depth-1; // Draw visualization image on the display if (oX!=X || oY!=Y || oZ!=Z || !visu0) { if (!visu0) { CImg tmp; if (depth==1) tmp = get_resize(disp.width,disp.height,1,cimg::min(3,dimv())); else tmp = (!phase?get_projections2d(X0,Y0,Z0):get_projections2d(X1,Y1,Z1)).get_resize(disp.width,disp.height,1,cimg::min(3,dimv())); if (old_normalization) { if (old_normalization<3 || cimg::type::is_float()) { if (sizeof(T)>1) visu0.assign(tmp.normalize(0,255)); else visu0.assign(tmp).normalize(0,255); } else { if (cimg::type::id()!=cimg::type::id()) { const float m = cimg::type::min(), M = cimg::type::max(); visu0.assign((CImg(tmp)-=m)*=255.0f/(M-m)); } else visu0.assign(tmp); } } else visu0.assign(tmp); } visu = visu0; const int d=(depth>1)?depth:0; if (phase) switch (feature_type) { case 1: { const int x0=(int)((X0+0.5f)*disp.width/(width+d)), y0=(int)((Y0+0.5f)*disp.height/(height+d)), x1=(int)((X1+0.5f)*disp.width/(width+d)), y1=(int)((Y1+0.5f)*disp.height/(height+d)); visu.draw_arrow(x0,y0,x1,y1,fgcolor,30.0f,5.0f,hatch); if (d) { const int zx0=(int)((width+Z0+0.5f)*disp.width/(width+d)), zx1=(int)((width+Z1+0.5f)*disp.width/(width+d)), zy0=(int)((height+Z0+0.5f)*disp.height/(height+d)), zy1=(int)((height+Z1+0.5f)*disp.height/(height+d)); visu.draw_arrow(zx0,y0,zx1,y1,fgcolor,30.0f,5.0f,hatch).draw_arrow(x0,zy0,x1,zy1,fgcolor,30.0f,5.0f,hatch); } } break; case 2: { const int x0=(X0=visu.dimy()-11) text_down = false; if (!feature_type || !phase) { if (X>=0 && Y>=0 && Z>=0 && X<(int)width && Y<(int)height && Z<(int)depth) { if (depth>1) std::sprintf(text,"Coords (%d,%d,%d)={ ",X,Y,Z); else std::sprintf(text,"Coords (%d,%d)={ ",X,Y); char *ctext = text + cimg::strlen(text), *const ltext = text+512; for (unsigned int k=0; k1) std::sprintf(text,"Vect (%d,%d,%d)-(%d,%d,%d), norm=%g",X0,Y0,Z0,X1,Y1,Z1,norm); else std::sprintf(text,"Vect (%d,%d)-(%d,%d), norm=%g",X0,Y0,X1,Y1,norm); } break; case 2: if (depth>1) std::sprintf(text,"Box (%d,%d,%d)-(%d,%d,%d), Size=(%d,%d,%d)", X01) std::sprintf(text,"Ellipse (%d,%d,%d)-(%d,%d,%d), Radii=(%d,%d,%d)", X0,Y0,Z0,X1,Y1,Z1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); else std::sprintf(text,"Ellipse (%d,%d)-(%d,%d), Radii=(%d,%d)", X0,Y0,X1,Y1,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); break; } if (phase || (mx>=0 && my>=0)) visu.draw_text(text,0,text_down?visu.dimy()-11:0,fgcolor,bgcolor,11,0.7f); disp.display(visu).wait(25); } else disp.wait(); if (disp.is_resized) { disp.resize(false); old_is_resized = true; disp.is_resized = false; visu0.assign(); } } // Return result if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; } if (feature_selected) { if (feature_type==2) { if (X0>X1) cimg::swap(X0,X1); if (Y0>Y1) cimg::swap(Y0,Y1); if (Z0>Z1) cimg::swap(Z0,Z1); } if (selection) { if (X1<0 || Y1<0 || Z1<0) X0=Y0=Z0=X1=Y1=Z1=-1; switch(feature_type) { case 1: case 2: selection[3] = X1; selection[4] = Y1; selection[5] = Z1; default: selection[0] = X0; selection[1] = Y0; selection[2] = Z0; } } } else if (selection) selection[0]=selection[1]=selection[2]=selection[3]=selection[4]=selection[5]=-1; disp.button = 0; disp.events = old_events; disp.normalization = old_normalization; disp.is_resized = old_is_resized; disp.key = key; return *this; } //! High-level interface to select features in images const CImg& feature_selection(int *const selection, const int feature_type, unsigned int *const XYZ=0,const unsigned char *const color=0) const { unsigned int w = width + (depth>1?depth:0), h = height + (depth>1?depth:0); const unsigned int dmin = cimg::min(w,h), minsiz = 256; if (dminmaxsiz) { w=w*maxsiz/dmax; h=h*maxsiz/dmax; } CImgDisplay disp(w,h," ",1,3); return feature_selection(selection,feature_type,disp,XYZ,color); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const CImg& points,const CImgList& primitives, const CImgList& colors, const CImgList& opacities, CImgDisplay& disp, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes=true, float *const pose_matrix=0) const { // Check input arguments if (!points || !primitives || !opacities) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points (%u), primitives (%u) or opacities (%u) are empty.", pixel_type(),points.size()/3,primitives.size,opacities.size); if (is_empty()) return CImg(disp.width,disp.height,1,colors[0].size(),0). display_object3d(points,primitives,colors,opacities,disp,centering, render_static,render_motion,double_sided,focale,ambient_light); if (points.height<3) return display_object3d(points.get_resize(-100,3,1,1,0),primitives,colors,opacities,disp, centering,render_static,render_motion,double_sided,focale,ambient_light); // Init 3D objects and compute object statistics CImg pose, rot_mat, centered_points = centering?CImg(points.width,3):CImg(), rotated_points(points.width,3), bbox_points, rotated_bbox_points, axes_points, rotated_axes_points; CImgList bbox_opacities, axes_opacities; CImgList bbox_colors, axes_colors; CImgList bbox_primitives, axes_primitives; float dx=0, dy=0, dz=0, ratio=1; const CImg bgcolor(1,1,1,dim,0), fgcolor(1,1,1,dim,cimg::type::max()); const CImgStats sx(points.get_shared_line(0),false), sy(points.get_shared_line(1),false), sz(points.get_shared_line(2),false); const float xm = (float)sx.min, xM = (float)sx.max, ym = (float)sy.min, yM = (float)sy.max, zm = (float)sz.min, zM = (float)sz.max, delta = cimg::max(xM-xm,yM-ym,zM-zm); if (display_axes) { axes_points.assign(7,3); rotated_axes_points.assign(7,3); axes_opacities.assign(3,1,1,1,1,1.0f); axes_colors.assign(3,dim,1,1,1,fgcolor[0]); axes_points(0,0) = 0; axes_points(0,1) = 0; axes_points(0,2) = 0; axes_points(1,0) = 20; axes_points(1,1) = 0; axes_points(1,2) = 0; axes_points(2,0) = 0; axes_points(2,1) = 20; axes_points(2,2) = 0; axes_points(3,0) = 0; axes_points(3,1) = 0; axes_points(3,2) = 20; axes_points(4,0) = 22; axes_points(4,1) = -6; axes_points(4,2) = 0; axes_points(5,0) = -6; axes_points(5,1) = 22; axes_points(5,2) = 0; axes_points(6,0) = -6; axes_points(6,1) = -6; axes_points(6,2) = 22; axes_primitives.insert(CImg::vector(0,1)); axes_primitives.insert(CImg::vector(0,2)); axes_primitives.insert(CImg::vector(0,3)); } // Begin user interaction loop CImg visu0(*this), visu; bool init = true, clicked = false, redraw = true; unsigned int key = 0; int x0 = 0, y0 = 0, x1 = 0, y1 = 0; const unsigned int old_events = disp.events; disp.show().button = disp.key = 0; disp.events = 3; while (!disp.is_closed && !key) { // Init object position and scale if necessary if (init) { ratio = delta>0?(2.0f*cimg::min(disp.width,disp.height)/(3.0f*delta)):0; dx = 0.5f*(xM+xm); dy = 0.5f*(yM+ym); dz = 0.5f*(zM+zm); if (centering) { cimg_forX(centered_points,l) { centered_points(l,0) = (float)((points(l,0)-dx)*ratio); centered_points(l,1) = (float)((points(l,1)-dy)*ratio); centered_points(l,2) = (float)((points(l,2)-dz)*ratio); } } if (render_static<0 || render_motion<0) { bbox_colors.assign(12,dim,1,1,1,fgcolor[0]); bbox_primitives.assign(12,1,2); bbox_points.assign(8,3); rotated_bbox_points.assign(8,3); bbox_points(0,0) = xm; bbox_points(0,1) = ym; bbox_points(0,2) = zm; bbox_points(1,0) = xM; bbox_points(1,1) = ym; bbox_points(1,2) = zm; bbox_points(2,0) = xM; bbox_points(2,1) = yM; bbox_points(2,2) = zm; bbox_points(3,0) = xm; bbox_points(3,1) = yM; bbox_points(3,2) = zm; bbox_points(4,0) = xm; bbox_points(4,1) = ym; bbox_points(4,2) = zM; bbox_points(5,0) = xM; bbox_points(5,1) = ym; bbox_points(5,2) = zM; bbox_points(6,0) = xM; bbox_points(6,1) = yM; bbox_points(6,2) = zM; bbox_points(7,0) = xm; bbox_points(7,1) = yM; bbox_points(7,2) = zM; bbox_primitives[0].fill(0,1); bbox_primitives[1].fill(1,2); bbox_primitives[2].fill(2,3); bbox_primitives[3].fill(3,0); bbox_primitives[4].fill(4,5); bbox_primitives[5].fill(5,6); bbox_primitives[6].fill(6,7); bbox_primitives[7].fill(7,4); bbox_primitives[8].fill(0,4); bbox_primitives[9].fill(1,5); bbox_primitives[10].fill(2,6); bbox_primitives[11].fill(3,7); bbox_opacities.assign(bbox_primitives.size,1,1,1,1,1.0f); } if (pose_matrix) pose = CImg(pose_matrix,4,4,1,1,false); else pose = CImg::identity_matrix(4); init = false; redraw = true; } // Rotate and Draw 3D object if (redraw) { const float r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0), r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1), r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2); if ((clicked && render_motion>=0) || (!clicked && render_static>=0)) { if (centering) cimg_forX(centered_points,l) { const float x = centered_points(l,0), y = centered_points(l,1), z = centered_points(l,2); rotated_points(l,0) = r00*x + r10*y + r20*z + r30; rotated_points(l,1) = r01*x + r11*y + r21*z + r31; rotated_points(l,2) = r02*x + r12*y + r22*z + r32; } else cimg_forX(points,l) { const float x = (float)points(l,0), y = (float)points(l,1), z = (float)points(l,2); rotated_points(l,0) = r00*x + r10*y + r20*z + r30; rotated_points(l,1) = r01*x + r11*y + r21*z + r31; rotated_points(l,2) = r02*x + r12*y + r22*z + r32; } } else { if (!centering) cimg_forX(bbox_points,l) { const float x = bbox_points(l,0), y = bbox_points(l,1), z = bbox_points(l,2); rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30; rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31; rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32; } else cimg_forX(bbox_points,l) { const float x = (bbox_points(l,0)-dx)*ratio, y = (bbox_points(l,1)-dy)*ratio, z = (bbox_points(l,2)-dz)*ratio; rotated_bbox_points(l,0) = r00*x + r10*y + r20*z + r30; rotated_bbox_points(l,1) = r01*x + r11*y + r21*z + r31; rotated_bbox_points(l,2) = r02*x + r12*y + r22*z + r32; } } // Draw object visu = visu0; if ((clicked && render_motion<0) || (!clicked && render_static<0)) visu.draw_object3d(visu.width/2.0f, visu.height/2.0f, 0, rotated_bbox_points,bbox_primitives,bbox_colors,bbox_opacities,1, false,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,0.2f); else visu.draw_object3d(visu.width/2.0f, visu.height/2.0f, 0, rotated_points,primitives,colors,opacities,clicked?render_motion:render_static, double_sided,focale,visu.dimx()/2.0f,visu.dimy()/2.0f,-5000.0f,ambient_light); // Draw axes if (display_axes) { const float Xaxes = 25.0f, Yaxes = visu.height-35.0f; cimg_forX(axes_points,l) { const float x = axes_points(l,0), y = axes_points(l,1), z = axes_points(l,2); rotated_axes_points(l,0) = r00*x + r10*y + r20*z; rotated_axes_points(l,1) = r01*x + r11*y + r21*z; rotated_axes_points(l,2) = r02*x + r12*y + r22*z; } axes_opacities(0,0) = (rotated_axes_points(1,2)>0)?0.5f:1.0f; axes_opacities(1,0) = (rotated_axes_points(2,2)>0)?0.5f:1.0f; axes_opacities(2,0) = (rotated_axes_points(3,2)>0)?0.5f:1.0f; visu.draw_object3d(Xaxes, Yaxes, 0, rotated_axes_points,axes_primitives,axes_colors,axes_opacities,1,false,focale,0,0,0,0). draw_text("X",(int)(Xaxes+rotated_axes_points(4,0)), (int)(Yaxes+rotated_axes_points(4,1)), axes_colors[0].ptr(), 0, 11, axes_opacities(0,0)). draw_text("Y",(int)(Xaxes+rotated_axes_points(5,0)), (int)(Yaxes+rotated_axes_points(5,1)), axes_colors[1].ptr(), 0, 11, axes_opacities(1,0)). draw_text("Z",(int)(Xaxes+rotated_axes_points(6,0)), (int)(Yaxes+rotated_axes_points(6,1)), axes_colors[2].ptr(), 0, 11, axes_opacities(2,0)); } visu.display(disp); if (!clicked || render_motion==render_static) redraw = false; } // Handle user interaction disp.wait(); if ((disp.button || disp.wheel) && disp.mouse_x>=0 && disp.mouse_y>=0) { redraw = true; if (!clicked) { x0 = x1 = disp.mouse_x; y0 = y1 = disp.mouse_y; if (!disp.wheel) clicked = true; } else { x1 = disp.mouse_x; y1 = disp.mouse_y; } if (disp.button&1) { const float R = 0.4f*cimg::min(disp.width,disp.height), R2 = R*R, u0 = (float)(x0-disp.dimx()/2), v0 = (float)(y0-disp.dimy()/2), u1 = (float)(x1-disp.dimx()/2), v1 = (float)(y1-disp.dimy()/2), n0 = (float)std::sqrt(u0*u0+v0*v0), n1 = (float)std::sqrt(u1*u1+v1*v1), nu0 = n0>R?(u0*R/n0):u0, nv0 = n0>R?(v0*R/n0):v0, nw0 = (float)std::sqrt(cimg::max(0.0f,R2-nu0*nu0-nv0*nv0)), nu1 = n1>R?(u1*R/n1):u1, nv1 = n1>R?(v1*R/n1):v1, nw1 = (float)std::sqrt(cimg::max(0.0f,R2-nu1*nu1-nv1*nv1)), u = nv0*nw1-nw0*nv1, v = nw0*nu1-nu0*nw1, w = nv0*nu1-nu0*nv1, n = (float)std::sqrt(u*u+v*v+w*w), alpha = (float)std::asin(n/R2); rot_mat = CImg::rotation_matrix(u,v,w,alpha); rot_mat *= pose.get_crop(0,0,2,2); pose.draw_image(rot_mat,0,0); x0=x1; y0=y1; } if (disp.button&2) { pose(3,2)+=(y1-y0); x0=x1; y0=y1; } if (disp.wheel) { pose(3,2)-=15*disp.wheel; disp.wheel=0; } if (disp.button&4) { pose(3,0)+=(x1-x0); pose(3,1)+=(y1-y0); x0=x1; y0=y1; } if ((disp.button&1) && (disp.button&2)) { init = true; disp.button = 0; x0 = x1; y0 = y1; pose = CImg::identity_matrix(4); } } else if (clicked) { x0=x1; y0=y1; clicked = false; redraw = true; } key = disp.key; if (key && key!=cimg::keyCTRLLEFT) { if (disp.is_pressed(cimg::keyCTRLLEFT)) { switch (key) { case cimg::keyD: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-200,-200); disp.is_resized = true; break; case cimg::keyC: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(-50,-50); disp.is_resized = true; break; case cimg::keyR: if (disp.is_fullscreen) disp.toggle_fullscreen(); disp.resize(*this); disp.is_resized = true; break; case cimg::keyF: disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen().is_resized = true; break; case cimg::keyS: { // Save snapshot static unsigned int snap_number = 0; char filename[32] = {0}; std::FILE *file; do { std::sprintf(filename,"CImg_%.4u.bmp",snap_number++); if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); } while (file); (+visu).draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Saving snapshot...",filename).display(disp); visu.save(filename); visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Snapshot '%s' saved.",filename).display(disp); } break; case cimg::keyO: { // Save object as an .OFF file static unsigned int snap_number = 0; char filename[32] = {0}; std::FILE *file; do { std::sprintf(filename,"CImg_%.4u.off",snap_number++); if ((file=std::fopen(filename,"r"))!=0) std::fclose(file); } while (file); visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Saving object...",filename).display(disp); points.save_off(filename,primitives,colors); visu.draw_text(2,2,fgcolor.ptr(),bgcolor.ptr(),11,1.0f,"Object '%s' saved.",filename).display(disp); } break; } disp.key = key = 0; } } else key = 0; if (disp.is_resized) { disp.resize(false); visu0 = get_resize(disp,1); redraw = true; } } if (pose_matrix) std::memcpy(pose_matrix,pose.data,16*sizeof(float)); disp.events = old_events; disp.button = 0; return *this; } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const CImgList& points,const CImgList& primitives, const CImgList& colors, const CImgList& opacities, CImgDisplay &disp, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes=true, float *const pose_matrix=0) const { CImg npoints(points.size,3,1,1,0); tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); cimg_forX(npoints,l) { const CImg& point = points[l]; const unsigned int siz = point.size(); if (!siz) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points (size=%u) contains a null element at " "position %u.",pixel_type(),points.size,l); *(ptrZ++) = (siz>2)?point(2):0; *(ptrY++) = (siz>1)?point(1):0; *(ptrX++) = point(0); } return display_object3d(npoints,primitives,colors,opacities,disp,centering, render_static,render_motion,double_sided,focale,ambient_light,display_axes,pose_matrix); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const CImg& points, const CImgList& primitives, const CImgList& colors, const CImg& opacities, CImgDisplay& disp, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes=true, float *const pose_matrix=0) const { CImgList nopacities(opacities.size(),1); cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); return display_object3d(points,primitives,colors,nopacities,disp,centering, render_static,render_motion,double_sided,focale,ambient_light,display_axes,pose_matrix); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const CImgList& points,const CImgList& primitives, const CImgList& colors, const CImg& opacities, CImgDisplay& disp, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes=true, float *const pose_matrix=0) const { CImgList nopacities(opacities.size(),1); cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); if (!points) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.", pixel_type()); CImg npoints(points.size,3,1,1,0); tp *ptrX = npoints.ptr(), *ptrY = npoints.ptr(0,1), *ptrZ = npoints.ptr(0,2); { cimg_forX(npoints,l) { const CImg& point = points[l]; const unsigned int siz = point.size(); if (!siz) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points (size=%u) contains a null element at " "position %u.",pixel_type(),points.size,l); *(ptrZ++) = (siz>2)?point(2):0; *(ptrY++) = (siz>1)?point(1):0; *(ptrX++) = point(0); } } return display_object3d(npoints,primitives,colors,nopacities,disp,centering, render_static,render_motion,double_sided,focale,ambient_light,display_axes,pose_matrix); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const tp& points, const CImgList& primitives, const CImgList& colors, const to& opacities, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const bool display_axes=true, float *const pose_matrix=0) const { CImgDisplay disp(width,height," ",0); return display_object3d(points,primitives,colors,opacities,disp,centering, render_static,render_motion,double_sided,focale,ambient_light,display_axes,pose_matrix); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const tp& points, const CImgList& primitives, const CImgList& colors, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const float opacity=1.0f, const bool display_axes=true, float *const pose_matrix=0) const { CImgDisplay disp(width,height," ",0); return display_object3d(points,primitives,colors,CImg::vector(opacity), disp,centering,render_static,render_motion,double_sided, focale,ambient_light,display_axes,pose_matrix); } //! High-level interface for displaying a 3d object template const CImg& display_object3d(const tp& points, const CImgList& primitives, const CImgList& colors, CImgDisplay &disp, const bool centering=true, const int render_static=4, const int render_motion=1, const bool double_sided=false, const float focale=500.0f, const float ambient_light=0.05f, const float opacity=1.0f, const bool display_axes=true, float *const pose_matrix=0) const { return display_object3d(points,primitives,colors,CImg::vector(opacity), disp,centering,render_static,render_motion,double_sided, focale,ambient_light,display_axes,pose_matrix); } //@} //---------------------- // //! \name Input-Output //@{ //---------------------- //! Load an image from a file. /** \param filename = name of the image file to load. \return A CImg instance containing the pixel data defined in the image file. \note The extension of \c filename defines the file format. If no filename extension is provided, CImg::get_load() will try to load a CRAW file (CImg Raw file). **/ static CImg get_load(const char *const filename) { const char *ext = cimg::filename_split(filename); if (!cimg::strncasecmp(ext,"asc",3)) return get_load_ascii(filename); if (!cimg::strncasecmp(ext,"dlm",3) || !cimg::strncasecmp(ext,"txt",3)) return get_load_dlm(filename); if (!cimg::strncasecmp(ext,"inr",3)) return get_load_inr(filename); if (!cimg::strncasecmp(ext,"hdr",3) || !cimg::strncasecmp(ext,"nii",3)) return get_load_analyze(filename); if (!cimg::strncasecmp(ext,"par",3) || !cimg::strncasecmp(ext,"rec",3)) return get_load_parrec(filename); if (!cimg::strncasecmp(ext,"pan",3)) return get_load_pandore(filename); if (!cimg::strncasecmp(ext,"bmp",3)) return get_load_bmp(filename); if (!cimg::strncasecmp(ext,"png",3)) return get_load_png(filename); if (!cimg::strncasecmp(ext,"tif",3)) return get_load_tiff(filename); if (!cimg::strncasecmp(ext,"jpg",3) || !cimg::strncasecmp(ext,"jpeg",4)) return get_load_jpeg(filename); if (!cimg::strncasecmp(ext,"ppm",3) || !cimg::strncasecmp(ext,"pgm",3) || !cimg::strncasecmp(ext,"pnm",3)) return get_load_pnm(filename); if (!cimg::strncasecmp(ext,"cimg",4) || ext[0]=='\0') return get_load_cimg(filename); if (!cimg::strncasecmp(ext,"dcm",3) || !cimg::strncasecmp(ext,"dicom",5)) return get_load_dicom(filename); return get_load_other(filename); } //! Load an image from a file /** This is the in-place version of get_load(). **/ CImg& load(const char *const filename) { return get_load(filename).swap(*this); } //! Load an image from an ASCII file. static CImg get_load_ascii(std::FILE *const file, const char *const filename=0) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); char line[256] = {0}; std::fscanf(nfile,"%255[^\n]",line); unsigned int off, dx = 0, dy = 1, dz = 1, dv = 1; int err = 1; std::sscanf(line,"%u %u %u %u",&dx,&dy,&dz,&dv); if (!dx || !dy || !dz || !dv) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_ascii() : File '%s' is not a valid .ASC file.\n" "Specified image dimensions are (%u,%u,%u,%u).", pixel_type(),filename?filename:"(FILE*)",dx,dy,dz,dv); } CImg dest(dx,dy,dz,dv); double val; T *ptr = dest.data; for (off=0; off::load_ascii() : File '%s', only %u/%u values read.", pixel_type(),filename?filename:"(FILE*)",off,dest.size()); if (!file) cimg::fclose(nfile); return dest; } //! Load an image from an ASCII file. static CImg get_load_ascii(const char *const filename) { return get_load_ascii(0,filename); } //! Load an image from an ASCII file (in-place version). CImg& load_ascii(std::FILE *const file, const char *const filename=0) { return get_load_ascii(file,filename).swap(*this); } //! Load an image from an ASCII file (in-place version). CImg& load_ascii(const char *const filename) { return get_load_ascii(filename).swap(*this); } //! Load an image from a DLM file static CImg get_load_dlm(std::FILE *const file, const char *const filename=0) { std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); CImg dest(256,256); char c, delimiter[256]={0}, tmp[256]; unsigned int cdx=0,dx=0,dy=0; int oerr=0, err; double val; while ((err = std::fscanf(nfile,"%lf%255[^0-9.eE+-]",&val,delimiter))!=EOF) { oerr = err; if (err>0) dest(cdx++,dy) = (T)val; if (cdx>=dest.width) dest.resize(dest.width+256,1,1,1,0); c=0; if (!std::sscanf(delimiter,"%255[^\n]%c",tmp,&c) || c=='\n') { dx = cimg::max(cdx,dx); dy++; if (dy>=dest.height) dest.resize(dest.width,dest.height+256,1,1,0); cdx=0; } } if (cdx && oerr==1) { dx=cdx; dy++; } if (!dx || !dy) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_dlm() : File '%s' is not a valid DLM file.\n" "Specified image dimensions are (%u,%u).", pixel_type(),filename?filename:"(FILE*)",dx,dy); } dest.resize(dx,dy,1,1,0); if (!file) cimg::fclose(nfile); return dest; } //! Load an image from a DLM file static CImg get_load_dlm(const char *const filename=0) { return get_load_dlm(0,filename); } //! Load an image from a DLM file (in-place version). CImg& load_dlm(std::FILE *const file, const char *const filename=0) { return get_load_dlm(file,filename).swap(*this); } //! Load an image from a DLM file (in-place version). CImg& load_dlm(const char *const filename) { return get_load_dlm(filename).swap(*this); } //! Load an image from a PNM file static CImg get_load_pnm(std::FILE *const file, const char *const filename=0) { std::FILE *const nfile=file?file:cimg::fopen(filename,"rb"); unsigned int ppm_type,width,height,colormax=255; char item[1024]={0}; int err; while ((err=std::fscanf(nfile,"%1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); if(std::sscanf(item," P%u",&ppm_type)!=1) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PNM header 'P?' not found.", pixel_type(),filename?filename:"(FILE*)"); } while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); if ((err=std::sscanf(item," %u %u %u",&width,&height,&colormax))<2) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_pnm() : File '%s', WIDTH and HEIGHT fields are not defined in PNM header.", pixel_type(),filename?filename:"(FILE*)"); } if (err==2) { while ((err=std::fscanf(nfile," %1023[^\n]",item))!=EOF && (item[0]=='#' || !err)) std::fgetc(nfile); cimg::warn(std::sscanf(item,"%u",&colormax)!=1, "CImg<%s>::load_pnm() : File '%s', COLORMAX field is not defined in PNM header.", pixel_type(),filename?filename:"(FILE*)"); } std::fgetc(nfile); CImg dest; int rval,gval,bval; switch (ppm_type) { case 2: { // Grey Ascii dest.assign(width,height,1,1); T* rdata = dest.ptr(); cimg_foroff(dest,off) { std::fscanf(nfile,"%d",&rval); *(rdata++)=(T)rval; } } break; case 3: { // Color Ascii dest.assign(width,height,1,3); T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); cimg_forXY(dest,x,y) { std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval); *(rdata++)=(T)rval; *(gdata++)=(T)gval; *(bdata++)=(T)bval; } } break; case 5: { // Grey Binary if (colormax<256) { // 8 bits CImg raw(width,height,1,1); cimg::fread(raw.data,width*height,nfile); dest=raw; } else { // 16 bits CImg raw(width,height,1,1); cimg::fread(raw.data,width*height,nfile); if (!cimg::endian()) cimg::endian_swap(raw.data,width*height); dest=raw; } } break; case 6: { // Color Binary if (colormax<256) { // 8 bits CImg raw(width,height,1,3); cimg::fread(raw.data,width*height*3,nfile); dest.assign(width,height,1,3); T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); const unsigned char *ptrs = raw.ptr(); for (unsigned int off = raw.width*raw.height; off; --off) { *(rdata++) = (T)*(ptrs++); *(gdata++) = (T)*(ptrs++); *(bdata++) = (T)*(ptrs++); } } else { // 16 bits CImg raw(width,height,1,3); cimg::fread(raw.data,width*height*3,nfile); if (!cimg::endian()) cimg::endian_swap(raw.data,width*height*3); dest.assign(width,height,1,3); T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); const unsigned short *ptrs = raw.ptr(); for (unsigned int off = raw.width*raw.height; off; --off) { *(rdata++) = (T)*(ptrs++); *(gdata++) = (T)*(ptrs++); *(bdata++) = (T)*(ptrs++); } } } break; default: if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_pnm() : File '%s', PPM type 'P%d' not supported.", pixel_type(),filename?filename:"(FILE*)",ppm_type); } if (!file) cimg::fclose(nfile); return dest; } //! Load an image from a PNM file. static CImg get_load_pnm(const char *const filename) { return get_load_pnm(0,filename); } //! Load an image from a PNM file (in-place version). CImg& load_pnm(std::FILE *const file, const char *const filename=0) { return get_load_pnm(file,filename).swap(*this); } //! Load an image from a PNM file (in-place version). CImg& load_pnm(const char *const filename) { return get_load_pnm(filename).swap(*this); } //! Load a YUV image sequence file. static CImg get_load_yuv(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb = false) { return CImgList::get_load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb).get_append('z','c'); } //! Load a YUV image sequence file. static CImg get_load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb = false) { return CImgList::get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).get_append('z','c'); } //! Load a YUV image sequence file (in-place). CImg& load_yuv(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb = false) { return get_load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); } //! Load a YUV image sequence file (in-place). CImg& load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb = false) { return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); } //! Load an image from a BMP file. static CImg get_load_bmp(std::FILE *const file, const char *const filename=0) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); unsigned char header[64]; cimg::fread(header,54,nfile); if (header[0]!='B' || header[1]!='M') { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_bmp() : File '%s' is not a valid BMP file.", pixel_type(),filename?filename:"(FILE*)"); } // Read header and pixel buffer int file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24), offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24), dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24), dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24), compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24), nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24), bpp = header[0x1C] + (header[0x1D]<<8), *palette = 0; const int dx_bytes = (bpp==1)?(dx/8+(dx%8?1:0)):((bpp==4)?(dx/2+(dx%2?1:0)):(dx*bpp/8)), align = (4-dx_bytes%4)%4, buf_size = cimg::min(cimg::abs(dy)*(dx_bytes+align),file_size-offset); if (bpp<16) { if (!nb_colors) nb_colors=1<0) std::fseek(nfile,xoffset,SEEK_CUR); unsigned char *buffer = new unsigned char[buf_size], *ptrs = buffer; cimg::fread(buffer,buf_size,nfile); if (!file) cimg::fclose(nfile); // Decompress buffer (if necessary) if (compression) { delete[] buffer; if (file) { throw CImgIOException("CImg<%s>::load_bmp() : Not able to read a compressed BMP file using a *FILE input",pixel_type()); } else return get_load_other(filename); } // Read pixel data CImg res(dx,cimg::abs(dy),1,3); switch (bpp) { case 1: { // Monochrome for (int y=res.height-1; y>=0; y--) { unsigned char mask = 0x80, val = 0; cimg_forX(res,x) { if (mask==0x80) val = *(ptrs++); const unsigned char *col = (unsigned char*)(palette+(val&mask?1:0)); res(x,y,2) = (T)*(col++); res(x,y,1) = (T)*(col++); res(x,y,0) = (T)*(col++); mask = cimg::ror(mask); } ptrs+=align; } } break; case 4: { // 16 colors for (int y=res.height-1; y>=0; y--) { unsigned char mask = 0xF0, val = 0; cimg_forX(res,x) { if (mask==0xF0) val = *(ptrs++); const unsigned char color = (mask<16)?(val&mask):((val&mask)>>4); unsigned char *col = (unsigned char*)(palette+color); res(x,y,2) = (T)*(col++); res(x,y,1) = (T)*(col++); res(x,y,0) = (T)*(col++); mask = cimg::ror(mask,4); } ptrs+=align; } } break; case 8: { // 256 colors for (int y=res.height-1; y>=0; y--) { cimg_forX(res,x) { const unsigned char *col = (unsigned char*)(palette+*(ptrs++)); res(x,y,2) = (T)*(col++); res(x,y,1) = (T)*(col++); res(x,y,0) = (T)*(col++); } ptrs+=align; } } break; case 16: { // 16 bits colors for (int y=res.height-1; y>=0; y--) { cimg_forX(res,x) { const unsigned char c1 = *(ptrs++), c2 = *(ptrs++); const unsigned short col = c1+(c2<<8); res(x,y,2) = (T)(col&0x1F); res(x,y,1) = (T)((col>>5)&0x1F); res(x,y,0) = (T)((col>>10)&0x1F); } ptrs+=align; } } break; case 24: { // 24 bits colors for (int y=res.height-1; y>=0; y--) { cimg_forX(res,x) { res(x,y,2) = (T)*(ptrs++); res(x,y,1) = (T)*(ptrs++); res(x,y,0) = (T)*(ptrs++); } ptrs+=align; } } break; case 32: { // 32 bits colors for (int y=res.height-1; y>=0; y--) { cimg_forX(res,x) { res(x,y,2) = (T)*(ptrs++); res(x,y,1) = (T)*(ptrs++); res(x,y,0) = (T)*(ptrs++); ptrs++; } ptrs+=align; } } break; } if (palette) delete[] palette; delete[] buffer; if (dy<0) res.mirror('y'); return res; } //! Load an image from a BMP file static CImg get_load_bmp(const char *const filename) { return get_load_bmp(0,filename); } //! Load an image from a BMP file CImg& load_bmp(std::FILE *const file, const char *const filename=0) { return get_load_bmp(file,filename).swap(*this); } //! Load an image from a BMP file CImg& load_bmp(const char *const filename) { return get_load_bmp(filename).swap(*this); } //! Load an image from a PNG file. // Note : Most of this function has been written by Eric Fausett static CImg get_load_png(std::FILE *const file, const char *const filename=0) { #ifndef cimg_use_png if (file) throw CImgIOException("CImg<%s>::load_png() : File '(FILE*)' cannot be read without using libpng.",pixel_type()); else return get_load_other(filename); #else // Open file and check for PNG validity std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); unsigned char pngCheck[8]; cimg::fread(pngCheck,8,nfile); if (png_sig_cmp(pngCheck,0,8)) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_png() : File '%s' is not a valid PNG file.", pixel_type(),filename?filename:"(FILE*)"); } // Setup PNG structures for read png_voidp user_error_ptr=0; png_error_ptr user_error_fn=0, user_warning_fn=0; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, // Verifies libpng version correct user_error_ptr, user_error_fn, user_warning_fn); if(!png_ptr){ if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'png_ptr' data structure.", pixel_type(),filename?filename:"(FILE*)"); } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr){ if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0); throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'info_ptr' data structure.", pixel_type(),filename?filename:"(FILE*)"); } png_infop end_info = png_create_info_struct(png_ptr); if(!end_info){ if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0); throw CImgIOException("CImg<%s>::load_png() : File '%s', trouble initializing 'end_info' data structure.", pixel_type(),filename?filename:"(FILE*)"); } // Error handling callback for png file reading if (setjmp(png_jmpbuf(png_ptr))){ if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); throw CImgIOException("CImg<%s>::load_png() : File '%s', unknown fatal error.", pixel_type(),filename?filename:"(FILE*)"); } png_init_io(png_ptr, nfile); png_set_sig_bytes(png_ptr, 8); // Get PNG Header Info up to data block png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type, interlace_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); int new_bit_depth = bit_depth; int new_color_type = color_type; // Transforms to unify image data if (new_color_type == PNG_COLOR_TYPE_PALETTE){ png_set_palette_to_rgb(png_ptr); new_color_type -= PNG_COLOR_MASK_PALETTE; new_bit_depth = 8; } if (new_color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8){ png_set_gray_1_2_4_to_8(png_ptr); new_bit_depth = 8; } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if (new_color_type == PNG_COLOR_TYPE_GRAY || new_color_type == PNG_COLOR_TYPE_GRAY_ALPHA){ png_set_gray_to_rgb(png_ptr); new_color_type |= PNG_COLOR_MASK_COLOR; } if (new_color_type == PNG_COLOR_TYPE_RGB) png_set_filler(png_ptr, 0xffffU, PNG_FILLER_AFTER); png_read_update_info(png_ptr, info_ptr); if (!(new_bit_depth==8 || new_bit_depth==16)) { if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong bit coding (bit_depth=%u)", pixel_type(),filename?filename:"(FILE*)",new_bit_depth); } const int byte_depth = new_bit_depth>>3; // Allocate Memory for Image Read png_bytep *imgData = new png_bytep[height]; for (unsigned int row=0; row < height; row++) imgData[row] = new png_byte[byte_depth * 4 * width]; png_read_image(png_ptr, imgData); png_read_end(png_ptr, end_info); // Read pixel data if (!(new_color_type==PNG_COLOR_TYPE_RGB || new_color_type==PNG_COLOR_TYPE_RGB_ALPHA)) { if (!file) cimg::fclose(nfile); png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); throw CImgIOException("CImg<%s>::load_png() : File '%s', wrong color coding (new_color_type=%u)", pixel_type(),filename?filename:"(FILE*)",new_color_type); } const bool no_alpha_channel = (new_color_type==PNG_COLOR_TYPE_RGB); CImg res(width,height,1,no_alpha_channel?3:4); const unsigned long off = width*height; T *ptr1 = res.data, *ptr2 = ptr1+off, *ptr3 = ptr2+off, *ptr4 = ptr3+off; switch(new_bit_depth){ case 8: { cimg_forY(res,y){ const unsigned char *ptrs = (unsigned char*)imgData[y]; cimg_forX(res,x){ *(ptr1++) = (T)*(ptrs++); *(ptr2++) = (T)*(ptrs++); *(ptr3++) = (T)*(ptrs++); if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++); } } } break; case 16: { cimg_forY(res,y){ const unsigned short *ptrs = (unsigned short*)(imgData[y]); cimg_forX(res,x){ *(ptr1++) = (T)*(ptrs++); *(ptr2++) = (T)*(ptrs++); *(ptr3++) = (T)*(ptrs++); if (no_alpha_channel) ptrs++; else *(ptr4++) = (T)*(ptrs++); } } } break; } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); // Deallocate Image Read Memory for (unsigned int n=0; n=3 TIFFSetWarningHandler(0); TIFFSetErrorHandler(0); #endif if (tif) { unsigned int number_of_directories = 0; do number_of_directories++; while (TIFFReadDirectory(tif)); uint16 samplesperpixel, bitspersample; uint32 nx,ny; TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx); TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny); TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel); if (samplesperpixel!=1 && samplesperpixel!=3 && samplesperpixel!=4) { cimg::warn(true,"CImg<%s>::load_tiff() : File '%s', unknow value for tag : TIFFTAG_SAMPLESPERPIXEL, will force it to 1.", pixel_type(),filename?filename:"(FILE*)"); samplesperpixel=1; } TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFClose(tif); tif = TIFFOpen(filename,"r"); dest.assign(nx,ny,number_of_directories,samplesperpixel); unsigned int dir=0; do { if (bitspersample!=8 || !( samplesperpixel == 3 || samplesperpixel == 4)){ //if !rgba 8bit uint16 photo, config; TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config); TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo); if (TIFFIsTiled(tif)) { uint32 tw, th; TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); if (config==PLANARCONFIG_CONTIG) { switch(bitspersample){ case 8:{ unsigned char *buf; buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif)); if (buf) { for (unsigned int row = 0; row::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { unsigned char * ptr = buf; for (unsigned int rr=row; rr::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { unsigned short * ptr = buf; for (unsigned int rr=row; rr::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { float * ptr = buf; for (unsigned int rr=row; rr::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { unsigned char * ptr = buf; for (unsigned int rr=row; rr::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { unsigned short * ptr = buf; for (unsigned int rr=row; rr::load_tiff() : File '%s', an error occure while reading a tile.", pixel_type(),filename?filename:"(FILE*)"); } else { float * ptr = buf; for (unsigned int rr=row; rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } unsigned char * ptr = buf; for (unsigned int rr=0; rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } unsigned short * ptr = buf; for (unsigned int rr=0; rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, 0); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } float * ptr = buf; for (unsigned int rr=0; rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, vv); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', an error occure while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } unsigned char * ptr = buf; for (unsigned int rr=0;rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, vv); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } unsigned short * ptr = buf; for (unsigned int rr=0;rrny?ny-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(tif, row, vv); if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { _TIFFfree(buf); TIFFClose(tif); throw CImgException("CImg<%s>::load_tiff() : File '%s', error while reading a strip.", pixel_type(),filename?filename:"(FILE*)"); } float * ptr = buf; for (unsigned int rr=0;rr::load_tiff() : File '%s', not enough memory for buffer allocation.", pixel_type(),filename?filename:"(FILE*)"); } TIFFReadRGBAImage(tif,nx,ny,raster,0); switch (samplesperpixel){ case 1:{ cimg_forXY(dest,x,y) dest(x,y,dir)=(T)(float)((raster[nx*(ny-1-y)+x]+ 128) / 257); break; } case 3:{ cimg_forXY(dest,x,y) { dest(x,y,dir,0)=(T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); dest(x,y,dir,1)=(T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); dest(x,y,dir,2)=(T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); } break; } case 4:{ cimg_forXY(dest,x,y) { dest(x,y,dir,0)=(T)(float)TIFFGetR(raster[nx*(ny-1-y)+x]); dest(x,y,dir,1)=(T)(float)TIFFGetG(raster[nx*(ny-1-y)+x]); dest(x,y,dir,2)=(T)(float)TIFFGetB(raster[nx*(ny-1-y)+x]); dest(x,y,dir,3)=(T)(float)TIFFGetA(raster[nx*(ny-1-y)+x]); } break; } } _TIFFfree(raster); } dir++; } while (TIFFReadDirectory(tif)); TIFFClose(tif); } else throw CImgException("CImg<%s>::load_tiff() : File '%s', error while loading the image.", pixel_type(),filename?filename:"(FILE*)"); return dest; #endif } //! Load an image from a TIFF file CImg& load_tiff(const char *const filename) { return get_load_tiff(filename).swap(*this); } //! Load a file in JPEG format. static CImg get_load_jpeg(std::FILE *const file, const char *const filename=0) { #ifndef cimg_use_jpeg if (file) throw CImgIOException("CImg<%s>::load_jpeg() : File '(FILE*)' cannot be read without using libjpeg.", pixel_type()); else return get_load_other(filename); #else struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo,nfile); jpeg_read_header(&cinfo,TRUE); jpeg_start_decompress(&cinfo); if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) { cimg::warn(true,"CImg<%s>::load_jpeg() : Don't know how to read image '%s' with libpeg, trying ImageMagick's convert", pixel_type(),filename?filename:"(unknown)"); if (!file) return get_load_other(filename); else { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_jpeg() : Cannot read JPEG image '%s' using a *FILE input.", pixel_type(),filename?filename:"(FILE*)"); } } const unsigned int row_stride = cinfo.output_width * cinfo.output_components; unsigned char *buf = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components], *buf2 = buf; JSAMPROW row_pointer[1]; while (cinfo.output_scanline < cinfo.output_height) { row_pointer[0] = &buf[cinfo.output_scanline*row_stride]; jpeg_read_scanlines(&cinfo,row_pointer,1); } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); if (!file) cimg::fclose(nfile); CImg dest(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); switch (dest.dim) { case 1: { T *ptr_g = dest.ptr(); cimg_forXY(dest,x,y) *(ptr_g++) = (T)*(buf2++); } break; case 3: { T *ptr_r = dest.ptr(0,0,0,0), *ptr_g = dest.ptr(0,0,0,1), *ptr_b = dest.ptr(0,0,0,2); cimg_forXY(dest,x,y) { *(ptr_r++) = (T)*(buf2++); *(ptr_g++) = (T)*(buf2++); *(ptr_b++) = (T)*(buf2++); } } break; case 4: { T *ptr_r = dest.ptr(0,0,0,0), *ptr_g = dest.ptr(0,0,0,1), *ptr_b = dest.ptr(0,0,0,2), *ptr_a = dest.ptr(0,0,0,3); cimg_forXY(dest,x,y) { *(ptr_r++) = (T)*(buf2++); *(ptr_g++) = (T)*(buf2++); *(ptr_b++) = (T)*(buf2++); *(ptr_a++) = (T)*(buf2++); } } break; } delete[] buf; return dest; #endif } //! Load an image from a JPEG file static CImg get_load_jpeg(const char *const filename) { return get_load_jpeg(0,filename); } //! Load an image from a JPEG file CImg& load_jpeg(std::FILE *const file, const char *const filename=0) { return get_load_jpeg(file,filename).swap(*this); } //! Load an image from a JPEG file CImg& load_jpeg(const char *const filename) { return get_load_jpeg(filename).swap(*this); } //! Load an image using builtin ImageMagick++ Library /** Added April/may 2006 by Christoph Hormann This is experimental code, not much tested, use with care. **/ static CImg get_load_magick(const char *const filename) { CImg dest; #ifdef cimg_use_magick Magick::Image image(filename); const unsigned int width = image.size().width(), height = image.size().height(); switch (image.type()) { case Magick::PaletteMatteType: case Magick::TrueColorMatteType: case Magick::ColorSeparationType: { dest.assign(width,height,1,4); T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2), *adata = dest.ptr(0,0,0,3); Magick::PixelPacket *pixels = image.getPixels(0,0,width,height); for (unsigned int off = width*height; off; --off) { *(rdata++) = (T)(pixels->red); *(gdata++) = (T)(pixels->green); *(bdata++) = (T)(pixels->blue); *(adata++) = (T)(pixels->opacity); pixels++; } } break; case Magick::PaletteType: case Magick::TrueColorType: { dest.assign(width,height,1,3); T *rdata = dest.ptr(0,0,0,0), *gdata = dest.ptr(0,0,0,1), *bdata = dest.ptr(0,0,0,2); Magick::PixelPacket *pixels = image.getPixels(0,0,width,height); for (unsigned int off = width*height; off; --off) { *(rdata++) = (T)(pixels->red); *(gdata++) = (T)(pixels->green); *(bdata++) = (T)(pixels->blue); pixels++; } } break; case Magick::GrayscaleMatteType: { dest.assign(width,height,1,2); T *data = dest.ptr(0,0,0,0), *adata = dest.ptr(0,0,0,1); Magick::PixelPacket *pixels = image.getPixels(0,0,width,height); for (unsigned int off = width*height; off; --off) { *(data++) = (T)(pixels->red); *(adata++) = (T)(pixels->opacity); pixels++; } } break; default: { dest.assign(width,height,1,1); T *data = dest.ptr(0,0,0,0); Magick::PixelPacket *pixels = image.getPixels(0,0,width,height); for (unsigned int off = width*height; off; --off) { *(data++) = (T)(pixels->red); pixels++; } } break; } return dest; #else throw CImgIOException("CImg<%s>::load_magick() : File '%s', Magick++ has not been linked during compilation.", pixel_type(),filename?filename:"(null)"); return dest; #endif } //! Load an image using builtin ImageMagick++ Library (in-place version). CImg& load_magick(const char *const filename) { return get_load_magick(filename).swap(*this); } //! Load an image from a RAW file. static CImg get_load_raw(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed=false, const bool endian_swap=false) { CImg res(sizex,sizey,sizez,sizev,0); if (!res) return res; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); if (!multiplexed) { cimg::fread(res.ptr(),res.size(),nfile); if (endian_swap) cimg::endian_swap(res.ptr(),res.size()); } else { CImg buf(1,1,1,sizev); cimg_forXYZ(res,x,y,z) { cimg::fread(buf.ptr(),sizev,nfile); if (endian_swap) cimg::endian_swap(buf.ptr(),sizev); res.set_vector_at(buf,x,y,z); } } if (!file) cimg::fclose(nfile); return res; } //! Load an image from a RAW file. static CImg get_load_raw(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed = false, const bool endian_swap = false) { return get_load_raw(0,filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap); } //! In-place version of get_load_raw() CImg& load_raw(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed = false, const bool endian_swap = false) { return get_load_raw(file,filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap).swap(*this); } //! In-place version of get_load_raw() CImg& load_raw(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int sizez=1, const unsigned int sizev=1, const bool multiplexed = false, const bool endian_swap = false) { return get_load_raw(filename,sizex,sizey,sizez,sizev,multiplexed,endian_swap).swap(*this); } //! Load an image from a RGBA file. static CImg get_load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); unsigned char *buffer = new unsigned char[dimw*dimh*4]; cimg::fread(buffer,dimw*dimh*4,nfile); if (!file) cimg::fclose(nfile); CImg res(dimw,dimh,1,4); T *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB = res.ptr(0,0,0,2), *pA = res.ptr(0,0,0,3); const unsigned char *ptrs = buffer; for (unsigned int off=res.width*res.height; off>0; --off) { *(pR++) = (T)*(ptrs++); *(pG++) = (T)*(ptrs++); *(pB++) = (T)*(ptrs++); *(pA++) = (T)*(ptrs++); } delete[] buffer; return res; } //! Load an image from a RGBA file. static CImg get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgba(0,filename,dimw,dimh); } //! In-place version of get_load_rgba() CImg& load_rgba(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgba(file, filename,dimw,dimh).swap(*this); } //! In-place version of get_load_rgba() CImg& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgba(filename,dimw,dimh).swap(*this); } //! Load an image from a RGB file. static CImg get_load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); unsigned char *buffer = new unsigned char[dimw*dimh*3]; cimg::fread(buffer,dimw*dimh*3,nfile); if (!file) cimg::fclose(nfile); CImg res(dimw,dimh,1,3); T *pR = res.ptr(0,0,0,0), *pG = res.ptr(0,0,0,1), *pB=res.ptr(0,0,0,2); const unsigned char *ptrs = buffer; for (unsigned int off=res.width*res.height; off>0; --off) { *(pR++) = (T)*(ptrs++); *(pG++) = (T)*(ptrs++); *(pB++) = (T)*(ptrs++); } delete[] buffer; return res; } //! Load an image from a RGB file. static CImg get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgb(0,filename,dimw,dimh); } //! In-place version of get_load_rgb() CImg& load_rgb(std::FILE *const file, const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgb(file, filename,dimw,dimh).swap(*this); } //! In-place version of get_load_rgb() CImg& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh) { return get_load_rgb(filename,dimw,dimh).swap(*this); } #define cimg_load_inr_case(Tf,sign,pixsize,Ts) \ if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ Ts *xval, *val = new Ts[fopt[0]*fopt[3]]; \ cimg_forYZ(dest,y,z) { \ cimg::fread(val,fopt[0]*fopt[3],nfile); \ if (fopt[7]!=endian) cimg::endian_swap(val,fopt[0]*fopt[3]); \ xval = val; cimg_forX(dest,x) cimg_forV(dest,k) \ dest(x,y,z,k) = (T)*(xval++); \ } \ delete[] val; \ loaded = true; \ } static void _load_inr(std::FILE *file, int out[8], float *const voxsize=0) { char item[1024],tmp1[64],tmp2[64]; out[0]=out[1]=out[2]=out[3]=out[5]=1; out[4]=out[6]=out[7]=-1; std::fscanf(file,"%63s",item); if(cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) throw CImgIOException("CImg<%s>::load_inr() : File does not appear to be a valid INR file.\n" "(INRIMAGE-4 identifier not found)",pixel_type()); while (std::fscanf(file," %63[^\n]%*c",item)!=EOF && cimg::strncmp(item,"##}",3)) { std::sscanf(item," XDIM%*[^0-9]%d",out); std::sscanf(item," YDIM%*[^0-9]%d",out+1); std::sscanf(item," ZDIM%*[^0-9]%d",out+2); std::sscanf(item," VDIM%*[^0-9]%d",out+3); std::sscanf(item," PIXSIZE%*[^0-9]%d",out+6); if (voxsize) { std::sscanf(item," VX%*[^0-9.eE+-]%f",voxsize); std::sscanf(item," VY%*[^0-9.eE+-]%f",voxsize+1); std::sscanf(item," VZ%*[^0-9.eE+-]%f",voxsize+2); } if (std::sscanf(item," CPU%*[ =]%s",tmp1)) out[7]=cimg::strncasecmp(tmp1,"sun",3)?0:1; switch(std::sscanf(item," TYPE%*[ =]%s %s",tmp1,tmp2)) { case 0: break; case 2: out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; std::strcpy(tmp1,tmp2); case 1: if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4]=0; if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4]=1; if (!cimg::strncasecmp(tmp1,"packed",6)) out[4]=2; if (out[4]>=0) break; default: throw CImgIOException("cimg::inr_header_read() : Invalid TYPE '%s'",tmp2); } } if(out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) throw CImgIOException("CImg<%s>::load_inr() : Bad dimensions in .inr file = ( %d , %d , %d , %d )", pixel_type(),out[0],out[1],out[2],out[3]); if(out[4]<0 || out[5]<0) throw CImgIOException("CImg<%s>::load_inr() : TYPE is not fully defined",pixel_type()); if(out[6]<0) throw CImgIOException("CImg<%s>::load_inr() : PIXSIZE is not fully defined",pixel_type()); if(out[7]<0) throw CImgIOException("CImg<%s>::load_inr() : Big/Little Endian coding type is not defined",pixel_type()); } //! Load an image from an INRIMAGE-4 file. static CImg get_load_inr(std::FILE *const file, const char *const filename=0, float *voxsize=0) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); int fopt[8], endian=cimg::endian()?1:0; bool loaded = false; if (voxsize) voxsize[0]=voxsize[1]=voxsize[2]=1; _load_inr(nfile,fopt,voxsize); CImg dest(fopt[0],fopt[1],fopt[2],fopt[3]); cimg_load_inr_case(0,0,8, unsigned char); cimg_load_inr_case(0,1,8, char); cimg_load_inr_case(0,0,16,unsigned short); cimg_load_inr_case(0,1,16,short); cimg_load_inr_case(0,0,32,unsigned int); cimg_load_inr_case(0,1,32,int); cimg_load_inr_case(1,0,32,float); cimg_load_inr_case(1,1,32,float); cimg_load_inr_case(1,0,64,double); cimg_load_inr_case(1,1,64,double); if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_inr() : File '%s', cannot read images of the type specified in the file", pixel_type(),filename?filename:"(FILE*)"); } if (!file) cimg::fclose(nfile); return dest; } //! Load an image from an INRIMAGE-4 file. static CImg get_load_inr(const char *const filename, float *const voxsize=0) { return get_load_inr(0,filename,voxsize); } //! In-place version of get_load_inr() CImg& load_inr(std::FILE *const file, const char *const filename=0, float *const voxsize=0) { return get_load_inr(file,filename,voxsize).swap(*this); } //! In-place version of get_load_inr() CImg& load_inr(const char *const filename, float *const voxsize=0) { return get_load_inr(filename,voxsize).swap(*this); } #define cimg_load_pandore_case(nid,nbdim,nwidth,nheight,ndepth,ndim,stype) \ case nid: { \ cimg::fread(dims,nbdim,nfile); \ if (endian) cimg::endian_swap(dims,nbdim); \ dest.assign(nwidth,nheight,ndepth,ndim); \ stype *buffer = new stype[dest.size()]; \ cimg::fread(buffer,dest.size(),nfile); \ if (endian) cimg::endian_swap(buffer,dest.size()); \ T *ptrd = dest.ptr(); \ cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); \ buffer-=dest.size(); \ delete[] buffer; \ } \ break; //! Load an image from a PANDORE-5 file. static CImg get_load_pandore(std::FILE *const file, const char *const filename=0) { std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; CImg dest; char tmp[32]; cimg::fread(tmp,12,nfile); if (cimg::strncasecmp("PANDORE",tmp,7)) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_pandore() : File '%s' is not a valid PANDORE file.\n" "(PANDORE identifier not found).",pixel_type(),filename?filename:"(FILE*)"); } unsigned int imageid,dims[8]; int ptbuf[4]; cimg::fread(&imageid,1,nfile); const bool endian = (imageid>255); if (endian) cimg::endian_swap(imageid); cimg::fread(tmp,20,nfile); switch (imageid) { cimg_load_pandore_case(2,2,dims[1],1,1,1,uchar); cimg_load_pandore_case(3,2,dims[1],1,1,1,long); cimg_load_pandore_case(4,2,dims[1],1,1,1,float); cimg_load_pandore_case(5,3,dims[2],dims[1],1,1,uchar); cimg_load_pandore_case(6,3,dims[2],dims[1],1,1,long); cimg_load_pandore_case(7,3,dims[2],dims[1],1,1,float); cimg_load_pandore_case(8,4,dims[3],dims[2],dims[1],1,uchar); cimg_load_pandore_case(9,4,dims[3],dims[2],dims[1],1,long); cimg_load_pandore_case(10,4,dims[3],dims[2],dims[1],1,float); case 11: { // Region 1D cimg::fread(dims,3,nfile); if (endian) cimg::endian_swap(dims,3); dest.assign(dims[1],1,1,1); if (dims[2]<256) { unsigned char *buffer = new unsigned char[dest.size()]; cimg::fread(buffer,dest.size(),nfile); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { if (dims[2]<65536) { unsigned short *buffer = new unsigned short[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { unsigned int *buffer = new unsigned int[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } } } break; case 12: { // Region 2D cimg::fread(dims,4,nfile); if (endian) cimg::endian_swap(dims,4); dest.assign(dims[2],dims[1],1,1); if (dims[3]<256) { unsigned char *buffer = new unsigned char[dest.size()]; cimg::fread(buffer,dest.size(),nfile); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { if (dims[3]<65536) { unsigned short *buffer = new unsigned short[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { unsigned long *buffer = new unsigned long[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } } } break; case 13: { // Region 3D cimg::fread(dims,5,nfile); if (endian) cimg::endian_swap(dims,5); dest.assign(dims[3],dims[2],dims[1],1); if (dims[4]<256) { unsigned char *buffer = new unsigned char[dest.size()]; cimg::fread(buffer,dest.size(),nfile); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { if (dims[4]<65536) { unsigned short *buffer = new unsigned short[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } else { unsigned int *buffer = new unsigned int[dest.size()]; cimg::fread(buffer,dest.size(),nfile); if (endian) cimg::endian_swap(buffer,dest.size()); T *ptrd = dest.ptr(); cimg_foroff(dest,off) *(ptrd++) = (T)*(buffer++); buffer-=dest.size(); delete[] buffer; } } } break; cimg_load_pandore_case(16,4,dims[2],dims[1],1,3,uchar); cimg_load_pandore_case(17,4,dims[2],dims[1],1,3,long); cimg_load_pandore_case(18,4,dims[2],dims[1],1,3,float); cimg_load_pandore_case(19,5,dims[3],dims[2],dims[1],3,uchar); cimg_load_pandore_case(20,5,dims[3],dims[2],dims[1],3,long); cimg_load_pandore_case(21,5,dims[3],dims[2],dims[1],3,float); cimg_load_pandore_case(22,2,dims[1],1,1,dims[0],uchar); cimg_load_pandore_case(23,2,dims[1],1,1,dims[0],long); cimg_load_pandore_case(24,2,dims[1],1,1,dims[0],ulong); cimg_load_pandore_case(25,2,dims[1],1,1,dims[0],float); cimg_load_pandore_case(26,3,dims[2],dims[1],1,dims[0],uchar); cimg_load_pandore_case(27,3,dims[2],dims[1],1,dims[0],long); cimg_load_pandore_case(28,3,dims[2],dims[1],1,dims[0],ulong); cimg_load_pandore_case(29,3,dims[2],dims[1],1,dims[0],float); cimg_load_pandore_case(30,4,dims[3],dims[2],dims[1],dims[0],uchar); cimg_load_pandore_case(31,4,dims[3],dims[2],dims[1],dims[0],long); cimg_load_pandore_case(32,4,dims[3],dims[2],dims[1],dims[0],ulong); cimg_load_pandore_case(33,4,dims[3],dims[2],dims[1],dims[0],float); case 34: // Points 1D cimg::fread(ptbuf,1,nfile); if (endian) cimg::endian_swap(ptbuf,1); dest.assign(1); dest[0]=(T)ptbuf[0]; break; case 35: // Points 2D cimg::fread(ptbuf,2,nfile); if (endian) cimg::endian_swap(ptbuf,2); dest.assign(2); dest[0]=(T)ptbuf[1]; dest[1]=(T)ptbuf[0]; break; case 36: // Points 3D cimg::fread(ptbuf,3,nfile); if (endian) cimg::endian_swap(ptbuf,3); dest.assign(3); dest[0]=(T)ptbuf[2]; dest[1]=(T)ptbuf[1]; dest[2]=(T)ptbuf[0]; break; default: if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_pandore() : File '%s', cannot read images with ID_type=%u", pixel_type(),filename?filename:"(FILE*)",imageid); } if (!file) cimg::fclose(nfile); return dest; } //! Load an image from a PANDORE-5 file. static CImg get_load_pandore(const char *const filename) { return get_load_pandore(0,filename); } //! In-place version of get_load_pandore() CImg& load_pandore(std::FILE *const file, const char *const filename) { return get_load_pandore(file,filename).swap(*this); } //! In-place version of get_load_pandore() CImg& load_pandore(const char *const filename) { return get_load_pandore(filename).swap(*this); } //! Load an image from an ANALYZE7.5/NIFTI file static CImg get_load_analyze(const char *const filename, float *const voxsize=0) { // Open header and data files std::FILE *file_header=0, *file=0; bool error_file = false; char body[1024]; const char *ext = cimg::filename_split(filename,body); if (!cimg::strncasecmp(ext,"nii",3)) file_header = cimg::fopen(filename,"rb"); else { if (!cimg::strncasecmp(ext,"hdr",3) || !cimg::strncasecmp(ext,"img",3)) { std::sprintf(body+cimg::strlen(body),".hdr"); file_header = cimg::fopen(body,"rb"); if (!file_header) error_file = true; else { std::sprintf(body+cimg::strlen(body)-3,"img"); file = cimg::fopen(body,"rb"); if (!file) { cimg::fclose(file_header); error_file = true; } } } } if (error_file) throw CImgIOException("CImg<%s>::load_analyze() : Filename '%s', not recognized as an Analyze 7.5 or NIFTI file.", pixel_type(),filename); // Read header bool endian = false; unsigned int header_size; cimg::fread(&header_size,1,file_header); if (header_size>=4096) { endian = true; cimg::endian_swap(header_size); } unsigned char *header = new unsigned char[header_size]; cimg::fread(header+4,header_size-4,file_header); if (file) cimg::fclose(file_header); if (endian) { cimg::endian_swap((short*)(header+40),5); cimg::endian_swap((short*)(header+70),1); cimg::endian_swap((short*)(header+72),1); cimg::endian_swap((float*)(header+76),4); cimg::endian_swap((float*)(header+112),1); } unsigned short *dim = (unsigned short*)(header+40), dimx=1, dimy=1, dimz=1, dimv=1; cimg::warn(!dim[0],"CImg<%s>::load_analyze() : Specified image has zero dimensions.",pixel_type()); cimg::warn(dim[0]>4,"CImg<%s>::load_analyze() : Number of image dimension is %d, reading only the 4 first dimensions", pixel_type(),dim[0]); if (dim[0]>=1) dimx = dim[1]; if (dim[0]>=2) dimy = dim[2]; if (dim[0]>=3) dimz = dim[3]; if (dim[0]>=4) dimv = dim[4]; float scalefactor = *(float*)(header+112); if (scalefactor==0) scalefactor=1; const unsigned short datatype = *(short*)(header+70); if (voxsize) { const float *vsize = (float*)(header+76); voxsize[0] = vsize[1]; voxsize[1] = vsize[2]; voxsize[2] = vsize[3]; } delete[] header; // Read pixel data std::FILE *nfile = file?file:file_header; CImg dest(dimx,dimy,dimz,dimv); switch (datatype) { case 2: { unsigned char *buffer = new unsigned char[dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); cimg_foroff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 4: { short *buffer = new short[dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); cimg_foroff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 8: { int *buffer = new int[dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); cimg_foroff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 16: { float *buffer = new float[dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); cimg_foroff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; case 64: { double *buffer = new double[dimx*dimy*dimz*dimv]; cimg::fread(buffer,dimx*dimy*dimz*dimv,nfile); if (endian) cimg::endian_swap(buffer,dimx*dimy*dimz*dimv); cimg_foroff(dest,off) dest.data[off] = (T)(buffer[off]*scalefactor); delete[] buffer; } break; default: cimg::fclose(nfile); throw CImgIOException("CImg<%s>::load_analyze() : File '%s, cannot read images with 'datatype = %d'", pixel_type(),filename,datatype); } cimg::fclose(nfile); return dest; } //! In-place version of get_load_analyze() CImg& load_analyze(const char *const filename, float *const voxsize = 0) { return get_load_analyze(filename,voxsize).swap(*this); } //! Load PAR-REC (Philips) image file static CImg get_load_parrec(const char *const filename, const char axe='v', const char align='p') { return CImgList::get_load_parrec(filename).get_append(axe,align); } //! In-place version of get_load_parrec() CImg& load_parrec(const char *const filename, const char axis='v', const char align='p') { return get_load_parrec(filename,axis,align).swap(*this); } //! Load an image from a CImg RAW file static CImg get_load_cimg(std::FILE *const file, const char *const filename=0, const char axis='v', const char align='p') { return CImgList::get_load_cimg(file,filename).get_append(axis,align); } //! Load an image from a CImg RAW file static CImg get_load_cimg(const char *const filename, const char axis='v', const char align='p') { return get_load_cimg(0,filename,axis,align); } //! In-place version of get_load_cimg() CImg& load_cimg(std::FILE *const file, const char *const filename=0, const char axis='v', const char align='p') { return get_load_cimg(file,filename,axis,align).swap(*this); } //! In-place version of get_load_cimg() CImg& load_cimg(const char *const filename, const char axis='v', const char align='p') { return get_load_cimg(filename,axis,align).swap(*this); } //! Function that loads the image for other file formats that are not natively handled by CImg. //! This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). static CImg get_load_imagemagick(const char *const filename) { static bool first_time = true; char command[1024], filetmp[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } std::FILE *file = 0; do { std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); std::sprintf(command,"%s \"%s\" %s",cimg::imagemagick_path(),filename,filetmp); cimg::system(command,cimg::imagemagick_path()); if (!(file = std::fopen(filetmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException("CImg<%s>::load_imagemagick() : Failed to open image '%s'.\n\n" "Path of 'ImageMagick's convert' : \"%s\"\n" "Path of temporary filename : \"%s\"", pixel_type(),filename,cimg::imagemagick_path(),filetmp); } else cimg::fclose(file); const CImg dest = CImg::get_load_pnm(filetmp); std::remove(filetmp); return dest; } //! In-place version of get_load_imagemagick() CImg& load_imagemagick(const char *const filename) { return get_load_imagemagick(filename).swap(*this); } //! Function that loads the image for other file formats that are not natively handled by CImg. //! This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). static CImg get_load_graphicsmagick(const char *const filename) { static bool first_time = true; char command[1024], filetmp[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } std::FILE *file = 0; do { std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); std::sprintf(command,"%s convert \"%s\" %s",cimg::graphicsmagick_path(),filename,filetmp); cimg::system(command,cimg::graphicsmagick_path()); if (!(file = std::fopen(filetmp,"rb"))) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException("CImg<%s>::load_graphicsmagick() : Failed to open image '%s'.\n\n" "Path of 'GraphicsMagick's gm' : \"%s\"\n" "Path of temporary filename : \"%s\"", pixel_type(),filename,cimg::graphicsmagick_path(),filetmp); } else cimg::fclose(file); const CImg dest = CImg::get_load_pnm(filetmp); std::remove(filetmp); return dest; } //! In-place version of get_load_graphicsmagick() CImg& load_graphicsmagick(const char *const filename) { return get_load_graphicsmagick(filename).swap(*this); } //! Function that loads the image for other file formats that are not natively handled by CImg. //! This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). static CImg get_load_other(const char *const filename) { CImg res; const unsigned int odebug = cimg::exception_mode(); cimg::exception_mode() = 0; try { res.load_magick(filename); } catch (CImgException&) { try { res.load_imagemagick(filename); } catch (CImgException&) { try { res.load_graphicsmagick(filename); } catch (CImgException&) { res.assign(); } } } cimg::exception_mode()=odebug; if (!res) throw CImgIOException("CImg<%s>::load_other() : Failed to open image '%s'.\n" "Check you have either the ImageMagick or GraphicsMagick package installed.", pixel_type(),filename); return res; } //! In-place version of get_load_graphicsmagick() CImg& load_other(const char *const filename) { return get_load_other(filename).swap(*this); } //! Load an image from a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net ) static CImg get_load_dicom(const char *const filename) { static bool first_time = true; char command[1024], filetmp[512], body[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } cimg::fclose(cimg::fopen(filename,"r")); std::FILE *file; do { std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); std::sprintf(command,"%s -w -c anlz -o %s -f %s",cimg::medcon_path(),filetmp,filename); cimg::system(command); cimg::filename_split(filetmp,body); std::sprintf(command,"m000-%s.hdr",body); file = std::fopen(command,"rb"); if (!file) { throw CImgIOException("CImg<%s>::load_dicom() : Failed to open image '%s'.\n\n" "Path of 'medcon' : \"%s\"\n" "Path of temporary filename : \"%s\"", pixel_type(),filename,cimg::medcon_path(),filetmp); } else cimg::fclose(file); const CImg dest = CImg::get_load_analyze(command); std::remove(command); std::sprintf(command,"m000-%s.img",body); std::remove(command); return dest; } //! In-place version of get_load_dicom() CImg& load_dicom(const char *const filename) { return get_load_dicom(filename).swap(*this); } //! Load OFF files (GeomView 3D object files) template static CImg get_load_off(const char *const filename, CImgList& primitives, CImgList& colors, const bool invert_faces=false) { std::FILE *file=cimg::fopen(filename,"r"); unsigned int nb_points=0, nb_primitives=0, nb_read=0; char line[256] = { 0 }; int err; // Skip comments, and read magic string OFF do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) { cimg::fclose(file); throw CImgIOException("CImg<%s>::load_off() : File '%s', keyword 'OFF' not found.",pixel_type(),filename); } do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); if ((err = std::sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { cimg::fclose(file); throw CImgIOException("CImg<%s>::load_off() : File '%s', invalid vertices/primitives numbers.",pixel_type(),filename); } // Read points data CImg points(nb_points,3); float X=0,Y=0,Z=0; cimg_forX(points,l) { do { err = std::fscanf(file,"%255[^\n] ",line); } while (!err || (err==1 && line[0]=='#')); if ((err = std::sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { cimg::fclose(file); throw CImgIOException("CImg<%s>::load_off() : File '%s', cannot read point %u/%u.\n",pixel_type(),filename,l+1,nb_points); } points(l,0) = (T)X; points(l,1) = (T)Y; points(l,2) = (T)Z; } // Read primitive data primitives.assign(); colors.assign(); bool stopflag = false; while (!stopflag) { float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f; unsigned int prim=0, i0=0, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0; line[0]='\0'; if ((err = std::fscanf(file,"%u",&prim))!=1) stopflag=true; else { nb_read++; switch (prim) { case 1: { if ((err = std::fscanf(file,"%u%255[^\n] ",&i0,line))<2) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); primitives.insert(CImg::vector(i0)); colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); } } break; case 2: { if ((err = std::fscanf(file,"%u%u%255[^\n] ",&i0,&i1,line))<2) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); primitives.insert(CImg::vector(i0,i1)); colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); } } break; case 3: { if ((err = std::fscanf(file,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line))<3) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2)); else primitives.insert(CImg::vector(i0,i2,i1)); colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); } } break; case 4: { if ((err = std::fscanf(file,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line))<4) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2,i3)); else primitives.insert(CImg::vector(i0,i3,i2,i1)); colors.insert(CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); } } break; case 5: { if ((err = std::fscanf(file,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line))<5) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) { primitives.insert(CImg::vector(i0,i1,i2,i3)); primitives.insert(CImg::vector(i0,i3,i4)); } else { primitives.insert(CImg::vector(i0,i3,i2,i1)); primitives.insert(CImg::vector(i0,i4,i3)); } colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); ++nb_primitives; } } break; case 6: { if ((err = std::fscanf(file,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line))<6) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) { primitives.insert(CImg::vector(i0,i1,i2,i3)); primitives.insert(CImg::vector(i0,i3,i4,i5)); } else { primitives.insert(CImg::vector(i0,i3,i2,i1)); primitives.insert(CImg::vector(i0,i5,i4,i3)); } colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); ++nb_primitives; } } break; case 7: { if ((err = std::fscanf(file,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line))<7) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) { primitives.insert(CImg::vector(i0,i1,i3,i4)); primitives.insert(CImg::vector(i0,i4,i5,i6)); primitives.insert(CImg::vector(i1,i2,i3)); } else { primitives.insert(CImg::vector(i0,i4,i3,i1)); primitives.insert(CImg::vector(i0,i6,i5,i4)); primitives.insert(CImg::vector(i3,i2,i1)); } colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); ++(++nb_primitives); } } break; case 8: { if ((err = std::fscanf(file,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line))<7) { cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u.", pixel_type(),filename,nb_read,nb_primitives); std::fscanf(file,"%*[^\n] "); } else { std::sscanf(line,"%f%f%f",&c0,&c1,&c2); if (invert_faces) { primitives.insert(CImg::vector(i0,i1,i2,i3)); primitives.insert(CImg::vector(i0,i3,i4,i5)); primitives.insert(CImg::vector(i0,i5,i6,i7)); } else { primitives.insert(CImg::vector(i0,i3,i2,i1)); primitives.insert(CImg::vector(i0,i5,i4,i3)); primitives.insert(CImg::vector(i0,i7,i6,i5)); } colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); ++(++nb_primitives); } } break; default: cimg::warn(true,"CImg<%s>::load_off() : File '%s', invalid primitive %u/%u (%u vertices).", pixel_type(),filename,nb_read,nb_primitives,prim); std::fscanf(file,"%*[^\n] "); break; } } } cimg::fclose(file); cimg::warn(primitives.size!=nb_primitives, "CImg<%s>::load_off() : File '%s', read only %u primitives instead of %u as claimed in the header.", pixel_type(),filename,primitives.size,nb_primitives); return points; } //! In-place version of get_load_off() template CImg& load_off(const char *const filename, CImgList& primitives, CImgList& colors, const bool invert_faces=false) { return get_load_off(filename,primitives,colors,invert_faces).swap(*this); } //! Save the image as a file. /** The used file format is defined by the file extension in the filename \p filename.\n Parameter \p number can be used to add a 6-digit number to the filename before saving.\n If \p normalize is true, a normalized version of the image (between [0,255]) is saved. **/ const CImg& save(const char *const filename, const int number=-1) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); const char *ext = cimg::filename_split(filename); char nfilename[1024]; const char *const fn = (number>=0)?cimg::filename_number(filename,number,6,nfilename):filename; if (!cimg::strncasecmp(ext,"asc",3)) return save_ascii(fn); if (!cimg::strncasecmp(ext,"dlm",3) || !cimg::strncasecmp(ext,"txt",3)) return save_dlm(fn); if (!cimg::strncasecmp(ext,"inr",3)) return save_inr(fn); if (!cimg::strncasecmp(ext,"hdr",3) || !cimg::strncasecmp(ext,"nii",3)) return save_analyze(fn); if (!cimg::strncasecmp(ext,"dcm",3)) return save_dicom(fn); if (!cimg::strncasecmp(ext,"pan",3)) return save_pandore(fn); if (!cimg::strncasecmp(ext,"bmp",3)) return save_bmp(fn); if (!cimg::strncasecmp(ext,"png",3)) return save_png(fn); if (!cimg::strncasecmp(ext,"tif",3)) return save_tiff(fn); if (!cimg::strncasecmp(ext,"jpg",3) || !cimg::strncasecmp(ext,"jpeg",4)) return save_jpeg(fn); if (!cimg::strncasecmp(ext,"rgba",4)) return save_rgba(fn); if (!cimg::strncasecmp(ext,"rgb",3)) return save_rgb(fn); if (!cimg::strncasecmp(ext,"raw",3)) return save_raw(fn); if (!cimg::strncasecmp(ext,"cimg",4) || ext[0]=='\0') return save_cimg(fn); if (!cimg::strncasecmp(ext,"pgm",3) || !cimg::strncasecmp(ext,"ppm",3) || !cimg::strncasecmp(ext,"pnm",3)) return save_pnm(fn); if (!cimg::strncasecmp(ext,"yuv",3)) return save_yuv(fn,true); return save_other(fn); } //! Save the image as an ASCII file (ASCII Raw + simple header). const CImg& save_ascii(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_ascii() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); std::fprintf(nfile,"%u %u %u %u\n",width,height,depth,dim); const T* ptrs = data; cimg_forYZV(*this,y,z,v) { cimg_forX(*this,x) std::fprintf(nfile,"%g ",(double)*(ptrs++)); std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save the image as an ASCII file (ASCII Raw + simple header). const CImg& save_ascii(const char *const filename) const { return save_ascii(0,filename); } //! Save the image as a DLM file. const CImg& save_dlm(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(depth>1, "CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is volumetric. Pixel values along Z will be unrolled (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); cimg::warn(dim>1, "CImg<%s>::save_dlm() : Instance image (%u,%u,%u,%u,%p) is multispectral. Pixel values along V will be unrolled (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); const T* ptrs = data; cimg_forYZV(*this,y,z,v) { cimg_forX(*this,x) std::fprintf(nfile,"%g%s",(double)*(ptrs++),(x==(int)width-1)?"":","); std::fputc('\n',nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save the image as a DLM file. const CImg& save_dlm(const char *const filename) const { return save_dlm(0,filename); } //! Save the image as a PNM file. const CImg& save_pnm(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); const CImgStats st(*this,false); cimg::warn(depth>1, "CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); cimg::warn(dim>3, "CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); const double stmin = st.min, stmax = st.max; cimg::warn(stmin<0 || stmax>65535,"CImg<%s>::save_pnm() : Instance image (%u,%u,%u,%u,%p) has pixel values in [%g,%g]. Probable type overflow (file '%s').",pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const T *ptrR = ptr(0,0,0,0), *ptrG = (dim>=2)?ptr(0,0,0,1):ptrR, *ptrB = (dim>=3)?ptr(0,0,0,2):ptrR; const unsigned int buf_size = width*height*(dim==1?1:3); std::fprintf(nfile,"P%c\n# CREATOR: CImg : Original size=%ux%ux%ux%u\n%u %u\n%u\n", (dim==1?'5':'6'),width,height,depth,dim,width,height,(st.max)<256?255:65535); switch(dim) { case 1: { if ((st.max)<256) { // Binary PGM 8 bits unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd; cimg_forXY(*this,x,y) *(xptrd++) = (unsigned char)*(ptrR++); cimg::fwrite(ptrd,buf_size,nfile); delete[] ptrd; } else { // Binary PGM 16 bits unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd; cimg_forXY(*this,x,y) *(xptrd++) = (unsigned short)*(ptrR++); if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size); cimg::fwrite(ptrd,buf_size,nfile); delete[] ptrd; } } break; default: { if ((st.max)<256) { // Binary PPM 8 bits unsigned char *ptrd = new unsigned char[buf_size], *xptrd = ptrd; cimg_forXY(*this,x,y) { *(xptrd++) = (unsigned char)*(ptrR++); *(xptrd++) = (unsigned char)*(ptrG++); *(xptrd++) = (unsigned char)*(ptrB++); } cimg::fwrite(ptrd,buf_size,nfile); delete[] ptrd; } else { // Binary PPM 16 bits unsigned short *ptrd = new unsigned short[buf_size], *xptrd = ptrd; cimg_forXY(*this,x,y) { *(xptrd++) = (unsigned short)*(ptrR++); *(xptrd++) = (unsigned short)*(ptrG++); *(xptrd++) = (unsigned short)*(ptrB++); } if (!cimg::endian()) cimg::endian_swap(ptrd,buf_size); cimg::fwrite(ptrd,buf_size,nfile); delete[] ptrd; } } break; } if (!file) cimg::fclose(nfile); return *this; } //! Save the image as a PNM file. const CImg& save_pnm(const char *const filename) const { return save_pnm(0,filename); } //! Save an image as a Dicom file (need '(X)Medcon' : http://xmedcon.sourceforge.net ) const CImg& save_dicom(const char *const filename) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_dicom() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save_dicom() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); static bool first_time = true; char command[1024], filetmp[512], body[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } std::FILE *file; do { std::sprintf(filetmp,"CImg%.4d.hdr",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); save_analyze(filetmp); std::sprintf(command,"%s -w -c dicom -o %s -f %s",cimg::medcon_path(),filename,filetmp); cimg::system(command); std::remove(filetmp); cimg::filename_split(filetmp,body); std::sprintf(filetmp,"%s.img",body); std::remove(filetmp); std::sprintf(command,"m000-%s",filename); file = std::fopen(command,"rb"); if (!file) { cimg::fclose(cimg::fopen(filename,"r")); throw CImgIOException("CImg<%s>::save_dicom() : Failed to save image '%s'.\n\n" "Path of 'medcon' : \"%s\"\n" "Path of temporary filename : \"%s\"", pixel_type(),filename,cimg::medcon_path(),filetmp); } else cimg::fclose(file); std::rename(command,filename); return *this; } //! Save the image as an ANALYZE7.5 or NIFTI file. const CImg& save_analyze(const char *const filename, const float *const voxsize=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_analyze() : File '%s', instance image (%u,%u,%u,%u,%p) is empty.", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save_analyze() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); std::FILE *file; char header[348], hname[1024], iname[1024]; const char *ext = cimg::filename_split(filename); short datatype=-1; std::memset(header,0,348); if (!ext[0]) { std::sprintf(hname,"%s.hdr",filename); std::sprintf(iname,"%s.img",filename); } if (!cimg::strncasecmp(ext,"hdr",3)) { std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(iname+cimg::strlen(iname)-3,"img"); } if (!cimg::strncasecmp(ext,"img",3)) { std::strcpy(hname,filename); std::strcpy(iname,filename); std::sprintf(hname+cimg::strlen(iname)-3,"hdr"); } if (!cimg::strncasecmp(ext,"nii",3)) { std::strcpy(hname,filename); iname[0]=0; } ((int*)(header))[0] = 348; std::sprintf(header+4,"CImg"); std::sprintf(header+14," "); ((short*)(header+36))[0] = 4096; ((char*)(header+38))[0] = 114; ((short*)(header+40))[0] = 4; ((short*)(header+40))[1] = width; ((short*)(header+40))[2] = height; ((short*)(header+40))[3] = depth; ((short*)(header+40))[4] = dim; if (!cimg::strcasecmp(pixel_type(),"bool")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"char")) datatype = 2; if (!cimg::strcasecmp(pixel_type(),"unsigned short")) datatype = 4; if (!cimg::strcasecmp(pixel_type(),"short")) datatype = 4; if (!cimg::strcasecmp(pixel_type(),"unsigned int")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"int")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"unsigned long")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"long")) datatype = 8; if (!cimg::strcasecmp(pixel_type(),"float")) datatype = 16; if (!cimg::strcasecmp(pixel_type(),"double")) datatype = 64; if (datatype<0) throw CImgIOException("CImg<%s>::save_analyze() : Cannot save image '%s' since pixel type (%s)" "is not handled in Analyze7.5 specifications.\n", pixel_type(),filename,pixel_type()); ((short*)(header+70))[0] = datatype; ((short*)(header+72))[0] = sizeof(T); ((float*)(header+112))[0] = 1; ((float*)(header+76))[0] = 0; if (voxsize) { ((float*)(header+76))[1] = voxsize[0]; ((float*)(header+76))[2] = voxsize[1]; ((float*)(header+76))[3] = voxsize[2]; } else ((float*)(header+76))[1] = ((float*)(header+76))[2] = ((float*)(header+76))[3] = 1; file = cimg::fopen(hname,"wb"); cimg::fwrite(header,348,file); if (iname[0]) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } cimg::fwrite(data,size(),file); cimg::fclose(file); return *this; } //! Save the image as a CImg file (Binary RAW + simple header) const CImg& save_cimg(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_cimg() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_cimg() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); CImgList tmp(1); tmp[0].width = width; tmp[0].height = height; tmp[0].depth = depth; tmp[0].dim = dim; tmp[0].data = data; tmp.save_cimg(file,filename); tmp[0].width = tmp[0].height = tmp[0].depth = tmp[0].dim = 0; tmp[0].data = 0; return *this; } //! Save the image as a CImg file (Binary RAW + simple header) const CImg& save_cimg(const char *const filename) const { return save_cimg(0,filename); } //! Save the image as a RAW file const CImg& save_raw(std::FILE *const file, const char *const filename=0, const bool multiplexed=false) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_raw() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); if (!multiplexed) cimg::fwrite(data,size(),nfile); else { CImg buf(dim); cimg_forXYZ(*this,x,y,z) { cimg_forV(*this,k) buf[k] = (*this)(x,y,z,k); cimg::fwrite(buf.data,dim,nfile); } } if (!file) cimg::fclose(nfile); return *this; } //! Save the image as a RAW file const CImg& save_raw(const char *const filename=0, const bool multiplexed=false) const { return save_raw(0,filename,multiplexed); } //! Save the image using ImageMagick's convert. /** Function that saves the image for other file formats that are not natively handled by CImg, using the tool 'convert' from the ImageMagick package.\n This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install the ImageMagick package in order to get this function working properly (see http://www.imagemagick.org ). **/ const CImg& save_imagemagick(const char *const filename, const unsigned int quality=100) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_imagemagick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save_imagemagick() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); static bool first_time = true; char command[512],filetmp[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } std::FILE *file; do { if (dim==1) std::sprintf(filetmp,"%s%sCImg%.4d.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); else std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); save_pnm(filetmp); std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::imagemagick_path(),quality,filetmp,filename); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException("CImg<%s>::save_imagemagick() : Failed to save image '%s'.\n\n" "Path of 'convert' : \"%s\"\n" "Path of temporary filename : \"%s\"\n", pixel_type(),filename,cimg::imagemagick_path(),filetmp); if (file) cimg::fclose(file); std::remove(filetmp); return *this; } //! Save the image using GraphicsMagick's gm. /** Function that saves the image for other file formats that are not natively handled by CImg, using the tool 'gm' from the GraphicsMagick package.\n This is the case for all compressed image formats (GIF,PNG,JPG,TIF,...). You need to install the GraphicsMagick package in order to get this function working properly (see http://www.graphicsmagick.org ). **/ const CImg& save_graphicsmagick(const char *const filename, const unsigned int quality=100) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_graphicsmagick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s')", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save_graphicsmagick() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); static bool first_time = true; char command[512],filetmp[512]; if (first_time) { std::srand((unsigned int)::time(0)); first_time = false; } std::FILE *file; do { if (dim==1) std::sprintf(filetmp,"%s%sCImg%.4d.pgm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); else std::sprintf(filetmp,"%s%sCImg%.4d.ppm",cimg::temporary_path(),cimg_OS==2?"\\":"/",std::rand()%10000); if ((file=std::fopen(filetmp,"rb"))!=0) std::fclose(file); } while (file); save_pnm(filetmp); std::sprintf(command,"%s -quality %u%% %s \"%s\"",cimg::graphicsmagick_path(),quality,filetmp,filename); cimg::system(command); file = std::fopen(filename,"rb"); if (!file) throw CImgIOException("CImg<%s>::save_graphicsmagick() : Failed to save image '%s'.\n\n" "Path of 'gm' : \"%s\"\n" "Path of temporary filename : \"%s\"\n", pixel_type(),filename,cimg::graphicsmagick_path(),filetmp); if (file) cimg::fclose(file); std::remove(filetmp); return *this; } const CImg& save_other(const char *const filename, const unsigned int quality=100) const { const unsigned int odebug = cimg::exception_mode(); bool is_saved = true; cimg::exception_mode() = 0; try { save_magick(filename); } catch (CImgException&) { try { save_imagemagick(filename,quality); } catch (CImgException&) { try { save_graphicsmagick(filename,quality); } catch (CImgException&) { is_saved = false; } } } cimg::exception_mode() = odebug; if (!is_saved) throw CImgIOException("CImg<%s>::save_other() : File '%s' cannot be saved.\n" "Check you have either the ImageMagick or GraphicsMagick package installed.", pixel_type(),filename); return *this; } //! Save the image as an INRIMAGE-4 file. const CImg& save_inr(std::FILE *const file, const char *const filename=0, const float *const voxsize=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!filename) throw CImgArgumentException("CImg<%s>::save_inr() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); int inrpixsize=-1; const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; if (!cimg::strcasecmp(pixel_type(),"unsigned char")) { inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } if (!cimg::strcasecmp(pixel_type(),"char")) { inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; } if (!cimg::strcasecmp(pixel_type(),"unsigned short")) { inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; } if (!cimg::strcasecmp(pixel_type(),"short")) { inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; } if (!cimg::strcasecmp(pixel_type(),"unsigned int")) { inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"int")) { inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"float")) { inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; } if (!cimg::strcasecmp(pixel_type(),"double")) { inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; } if (inrpixsize<=0) throw CImgIOException("CImg<%s>::save_inr() : Don't know how to save images of '%s'",pixel_type(),pixel_type()); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); char header[257]; int err = std::sprintf(header,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n",width,height,depth,dim); if (voxsize) err += std::sprintf(header+err,"VX=%g\nVY=%g\nVZ=%g\n",voxsize[0],voxsize[1],voxsize[2]); err += std::sprintf(header+err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endian()?"sun":"decm"); std::memset(header+err,'\n',252-err); std::memcpy(header+252,"##}\n",4); cimg::fwrite(header,256,nfile); cimg_forXYZ(*this,x,y,z) cimg_forV(*this,k) cimg::fwrite(&((*this)(x,y,z,k)),1,nfile); if (!file) cimg::fclose(nfile); return *this; } //! Save the image as an INRIMAGE-4 file. const CImg& save_inr(const char *const filename, const float *const voxsize=0) const { return save_inr(0,filename,voxsize); } #define cimg_save_pandore_case(sy,sz,sv,stype,id) \ if (!saved && (sy?(sy==height):true) && (sz?(sz==depth):true) && (sv?(sv==dim):true) && !strcmp(stype,pixel_type())) { \ unsigned int *iheader = (unsigned int*)(header+12); \ nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ cimg::fwrite(header,36,nfile); \ cimg::fwrite(dims,nbdims,nfile); \ if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ unsigned char *buffer = new unsigned char[size()]; \ const T *ptrs = ptr(); \ cimg_foroff(*this,off) *(buffer++)=(unsigned char)(*(ptrs++)); \ buffer-=size(); \ cimg::fwrite(buffer,size(),nfile); \ delete[] buffer; \ } \ if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ unsigned long *buffer = new unsigned long[size()]; \ const T *ptrs = ptr(); \ cimg_foroff(*this,off) *(buffer++)=(long)(*(ptrs++)); \ buffer-=size(); \ cimg::fwrite(buffer,size(),nfile); \ delete[] buffer; \ } \ if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ float *buffer = new float[size()]; \ const T *ptrs = ptr(); \ cimg_foroff(*this,off) *(buffer++)=(float)(*(ptrs++)); \ buffer-=size(); \ cimg::fwrite(buffer,size(),nfile); \ delete[] buffer; \ } \ saved = true; \ } unsigned int _save_pandore_header_length(unsigned int id,unsigned int *dims,const unsigned int colorspace=0) const { unsigned int nbdims=0; if (id==2 || id==3 || id==4) { dims[0]=1; dims[1]=width; nbdims=2; } if (id==5 || id==6 || id==7) { dims[0]=1; dims[1]=height; dims[2]=width; nbdims=3; } if (id==8 || id==9 || id==10) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; } if (id==16 || id==17 || id==18) { dims[0]=3; dims[1]=height; dims[2]=width; dims[3]=colorspace; nbdims=4; } if (id==19 || id==20 || id==21) { dims[0]=3; dims[1]=depth; dims[2]=height; dims[3]=width; dims[4]=colorspace; nbdims=5; } if (id==22 || id==23 || id==25) { dims[0]=dim; dims[1]=width; nbdims=2; } if (id==26 || id==27 || id==29) { dims[0]=dim; dims[1]=height; dims[2]=width; nbdims=3; } if (id==30 || id==31 || id==33) { dims[0]=dim; dims[1]=depth; dims[2]=height; dims[3]=width; nbdims=4; } return nbdims; } //! Save the image as a PANDORE-5 file. const CImg& save_pandore(std::FILE *const file, const char *const filename=0, const unsigned int colorspace=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_pandore() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, 0,0,0,0, 'C','I','m','g',0,0,0,0,0, 'N','o',' ','d','a','t','e',0,0,0, 0 }; unsigned int nbdims,dims[5]; bool saved=false; cimg_save_pandore_case(1,1,1,"unsigned char",2); cimg_save_pandore_case(1,1,1,"char",3); cimg_save_pandore_case(1,1,1,"short",3); cimg_save_pandore_case(1,1,1,"unsigned short",3); cimg_save_pandore_case(1,1,1,"unsigned int",3); cimg_save_pandore_case(1,1,1,"int",3); cimg_save_pandore_case(1,1,1,"unsigned long",4); cimg_save_pandore_case(1,1,1,"long",3); cimg_save_pandore_case(1,1,1,"float",4); cimg_save_pandore_case(1,1,1,"double",4); cimg_save_pandore_case(0,1,1,"unsigned char",5); cimg_save_pandore_case(0,1,1,"char",6); cimg_save_pandore_case(0,1,1,"short",6); cimg_save_pandore_case(0,1,1,"unsigned short",6); cimg_save_pandore_case(0,1,1,"unsigned int",6); cimg_save_pandore_case(0,1,1,"int",6); cimg_save_pandore_case(0,1,1,"unsigned long",7); cimg_save_pandore_case(0,1,1,"long",6); cimg_save_pandore_case(0,1,1,"float",7); cimg_save_pandore_case(0,1,1,"double",7); cimg_save_pandore_case(0,0,1,"unsigned char",8); cimg_save_pandore_case(0,0,1,"char",9); cimg_save_pandore_case(0,0,1,"short",9); cimg_save_pandore_case(0,0,1,"unsigned short",9); cimg_save_pandore_case(0,0,1,"unsigned int",9); cimg_save_pandore_case(0,0,1,"int",9); cimg_save_pandore_case(0,0,1,"unsigned long",10); cimg_save_pandore_case(0,0,1,"long",9); cimg_save_pandore_case(0,0,1,"float",10); cimg_save_pandore_case(0,0,1,"double",10); cimg_save_pandore_case(0,1,3,"unsigned char",16); cimg_save_pandore_case(0,1,3,"char",17); cimg_save_pandore_case(0,1,3,"short",17); cimg_save_pandore_case(0,1,3,"unsigned short",17); cimg_save_pandore_case(0,1,3,"unsigned int",17); cimg_save_pandore_case(0,1,3,"int",17); cimg_save_pandore_case(0,1,3,"unsigned long",18); cimg_save_pandore_case(0,1,3,"long",17); cimg_save_pandore_case(0,1,3,"float",18); cimg_save_pandore_case(0,1,3,"double",18); cimg_save_pandore_case(0,0,3,"unsigned char",19); cimg_save_pandore_case(0,0,3,"char",20); cimg_save_pandore_case(0,0,3,"short",20); cimg_save_pandore_case(0,0,3,"unsigned short",20); cimg_save_pandore_case(0,0,3,"unsigned int",20); cimg_save_pandore_case(0,0,3,"int",20); cimg_save_pandore_case(0,0,3,"unsigned long",21); cimg_save_pandore_case(0,0,3,"long",20); cimg_save_pandore_case(0,0,3,"float",21); cimg_save_pandore_case(0,0,3,"double",21); cimg_save_pandore_case(1,1,0,"unsigned char",22); cimg_save_pandore_case(1,1,0,"char",23); cimg_save_pandore_case(1,1,0,"short",23); cimg_save_pandore_case(1,1,0,"unsigned short",23); cimg_save_pandore_case(1,1,0,"unsigned int",23); cimg_save_pandore_case(1,1,0,"int",23); cimg_save_pandore_case(1,1,0,"unsigned long",25); cimg_save_pandore_case(1,1,0,"long",23); cimg_save_pandore_case(1,1,0,"float",25); cimg_save_pandore_case(1,1,0,"double",25); cimg_save_pandore_case(0,1,0,"unsigned char",26); cimg_save_pandore_case(0,1,0,"char",27); cimg_save_pandore_case(0,1,0,"short",27); cimg_save_pandore_case(0,1,0,"unsigned short",27); cimg_save_pandore_case(0,1,0,"unsigned int",27); cimg_save_pandore_case(0,1,0,"int",27); cimg_save_pandore_case(0,1,0,"unsigned long",29); cimg_save_pandore_case(0,1,0,"long",27); cimg_save_pandore_case(0,1,0,"float",29); cimg_save_pandore_case(0,1,0,"double",29); cimg_save_pandore_case(0,0,0,"unsigned char",30); cimg_save_pandore_case(0,0,0,"char",31); cimg_save_pandore_case(0,0,0,"short",31); cimg_save_pandore_case(0,0,0,"unsigned short",31); cimg_save_pandore_case(0,0,0,"unsigned int",31); cimg_save_pandore_case(0,0,0,"int",31); cimg_save_pandore_case(0,0,0,"unsigned long",33); cimg_save_pandore_case(0,0,0,"long",31); cimg_save_pandore_case(0,0,0,"float",33); cimg_save_pandore_case(0,0,0,"double",33); if (!file) cimg::fclose(nfile); return *this; } //! Save the image as a PANDORE-5 file. const CImg& save_pandore(const char *const filename=0, const unsigned int colorspace=0) const { return save_pandore(0,filename,colorspace); } //! Save the image as a YUV video sequence file const CImg& save_yuv(std::FILE *const file, const char *const filename=0, const bool rgb2yuv=true) const { CImgList(*this).save_yuv(file,filename,rgb2yuv); return *this; } //! Save the image as a YUV video sequence file const CImg& save_yuv(const char *const filename, const bool rgb2yuv=true) const { return save_yuv(0,filename,rgb2yuv); } //! Save the image as a BMP file const CImg& save_bmp(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(depth>1, "CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); cimg::warn(dim>3, "CImg<%s>::save_bmp() : Instance image (%u,%u,%u,%u,%p) is multispectral. Only the three first channels will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); unsigned char header[54]={0}, align_buf[4]={0}; const unsigned int align = (4-(3*width)%4)%4, buf_size = (3*width+align)*dimy(), file_size = 54+buf_size; header[0] = 'B'; header[1] = 'M'; header[0x02]=file_size&0xFF; header[0x03]=(file_size>>8)&0xFF; header[0x04]=(file_size>>16)&0xFF; header[0x05]=(file_size>>24)&0xFF; header[0x0A]=0x36; header[0x0E]=0x28; header[0x12]=width&0xFF; header[0x13]=(width>>8)&0xFF; header[0x14]=(width>>16)&0xFF; header[0x15]=(width>>24)&0xFF; header[0x16]=height&0xFF; header[0x17]=(height>>8)&0xFF; header[0x18]=(height>>16)&0xFF; header[0x19]=(height>>24)&0xFF; header[0x1A]=1; header[0x1B]=0; header[0x1C]=24; header[0x1D]=0; header[0x22]=buf_size&0xFF; header[0x23]=(buf_size>>8)&0xFF; header[0x24]=(buf_size>>16)&0xFF; header[0x25]=(buf_size>>24)&0xFF; header[0x27]=0x1; header[0x2B]=0x1; cimg::fwrite(header,54,nfile); const T *pR = ptr(0,height-1,0,0), *pG = (dim>=2)?ptr(0,height-1,0,1):pR, *pB = (dim>=3)?ptr(0,height-1,0,2):pR; cimg_forY(*this,y) { cimg_forX(*this,x) { std::fputc((unsigned char)(*(pB++)),nfile); std::fputc((unsigned char)(*(pG++)),nfile); std::fputc((unsigned char)(*(pR++)),nfile); } cimg::fwrite(align_buf,align,nfile); pR-=2*width; pG-=2*width; pB-=2*width; } if (!file) cimg::fclose(nfile); return *this; } //! Save the image as a BMP file const CImg& save_bmp(const char *const filename) const { return save_bmp(0,filename); } //! Save an image to a PNG file. // Most of this function has been written by Eric Fausett /** \param filename = name of the png image file to save \return *this \note The png format specifies a variety of possible data formats. Grey scale, Grey scale with Alpha, RGB color, RGB color with Alpha, and Palletized color are supported. Per channel bit depths of 1, 2, 4, 8, and 16 are natively supported. The type of file saved depends on the number of channels in the CImg file. If there is 4 or more channels, the image will be saved as an RGB color with Alpha image using the bottom 4 channels. If there are 3 channels, the saved image will be an RGB color image. If 2 channels then the image saved will be Grey scale with Alpha, and if 1 channel will be saved as a Grey scale image. **/ const CImg& save_png(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!filename) throw CImgArgumentException("CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(depth>1, "CImg<%s>::save_png() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); #ifndef cimg_use_png if (!file) return save_other(filename); else throw CImgIOException("CImg<%s>::save_png() : Cannot save a PNG image in a *FILE output. Use libpng instead.", pixel_type()); #else std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); // Setup PNG structures for write png_voidp user_error_ptr=0; png_error_ptr user_error_fn=0, user_warning_fn=0; png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, user_error_ptr, user_error_fn, user_warning_fn); if(!png_ptr){ if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'png_ptr' data structure.", pixel_type(),filename?filename:"(unknown)"); } png_infop info_ptr = png_create_info_struct(png_ptr); if(!info_ptr){ png_destroy_write_struct(&png_ptr,(png_infopp)0); if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::save_png() : File '%s', error when initializing 'info_ptr' data structure.", pixel_type(),filename?filename:"(unknown)"); } if (setjmp(png_jmpbuf(png_ptr))){ png_destroy_write_struct(&png_ptr, &info_ptr); if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.", pixel_type(),filename?filename:"(unknown)"); } png_init_io(png_ptr, nfile); png_uint_32 width = dimx(); png_uint_32 height = dimy(); const CImgStats stats(*this,false); const float vmin = (float)stats.min, vmax = (float)stats.max; const int bit_depth = (vmin<0 || vmax>=256)?16:8; int color_type; switch (dimv()) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; default: color_type = PNG_COLOR_TYPE_RGB_ALPHA; } const int interlace_type = PNG_INTERLACE_NONE; const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; const int filter_method = PNG_FILTER_TYPE_DEFAULT; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_method); png_write_info(png_ptr, info_ptr); const int byte_depth = bit_depth>>3; const int numChan = dimv()>4?4:dimv(); const int pixel_bit_depth_flag = numChan * (bit_depth-1); // Allocate Memory for Image Save and Fill pixel data png_bytep *imgData = new png_byte*[height]; for(unsigned int row=0; row(imgData[y]); cimg_forX(*this,x) *(ptrs++) = (unsigned short)*(pC0++); } } break; case 30: { // Gray w/ Alpha 16-bit const T *pC1 = ptr(0,0,0,1); cimg_forY(*this,y){ unsigned short *ptrs = reinterpret_cast(imgData[y]); cimg_forX(*this,x) { *(ptrs++) = (unsigned short)*(pC0++); *(ptrs++) = (unsigned short)*(pC1++); } } } break; case 45: { // RGB 16-bit const T *pC1 = ptr(0,0,0,1); const T *pC2 = ptr(0,0,0,2); cimg_forY(*this,y) { unsigned short *ptrs = reinterpret_cast(imgData[y]); cimg_forX(*this,x) { *(ptrs++) = (unsigned short)*(pC0++); *(ptrs++) = (unsigned short)*(pC1++); *(ptrs++) = (unsigned short)*(pC2++); } } } break; case 60: { // RGB w/ Alpha 16-bit const T *pC1 = ptr(0,0,0,1); const T *pC2 = ptr(0,0,0,2); const T *pC3 = ptr(0,0,0,3); cimg_forY(*this,y) { unsigned short *ptrs = reinterpret_cast(imgData[y]); cimg_forX(*this,x) { *(ptrs++) = (unsigned short)*(pC0++); *(ptrs++) = (unsigned short)*(pC1++); *(ptrs++) = (unsigned short)*(pC2++); *(ptrs++) = (unsigned short)*(pC3++); } } } break; default: if (!file) cimg::fclose(nfile); throw CImgIOException("CImg<%s>::save_png() : File '%s', unknown fatal error.", pixel_type(),filename?filename:"(unknown)"); break; } png_write_image(png_ptr, imgData); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); // Deallocate Image Write Memory for (unsigned int n=0; n::save_tiff() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save_tiff() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); #ifdef cimg_use_tiff uint32 rowsperstrip = (uint32) -1; uint16 spp = dimv(), bpp = sizeof(T)*8; uint16 photometric; if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB; else photometric = PHOTOMETRIC_MINISBLACK; uint16 compression = COMPRESSION_NONE; TIFF *out; out = TIFFOpen(filename,"w"); if (out) { for (unsigned int dir=0; dirheight?height-row:rowsperstrip); tstrip_t strip = TIFFComputeStrip(out, row, 0); tsize_t i = 0; for (unsigned int rr=0; rr::save_tiff() : File '%s', an error occure while writing a strip.", pixel_type(),filename?filename:"(FILE*)"); } } _TIFFfree(buf); } TIFFWriteDirectory(out); } TIFFClose(out); } else throw CImgException("CImg<%s>::save_tiff() : File '%s', error while writing tiff file.", pixel_type(),filename); #else return save_other(filename); #endif return *this; } //! Save a file in JPEG format. const CImg& save_jpeg(std::FILE *const file, const char *const filename=0, const unsigned int quality=100) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p), specified filename is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(depth>1, "CImg<%s>::save_jpeg() : Instance image (%u,%u,%u,%u,%p) is volumetric. Only the first slice will be saved (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); #ifndef cimg_use_jpeg if (!file) return save_other(filename,quality); else throw CImgIOException("CImg<%s>::save_jpeg() : Cannot save a JPEG image in a *FILE output. Use libjpeg instead.", pixel_type()); #else // Fill pixel buffer unsigned char *buf; unsigned int dimbuf=0; J_COLOR_SPACE colortype=JCS_RGB; switch (dim) { case 1: { // Greyscale images unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=1)]; colortype = JCS_GRAYSCALE; const T *ptr_g = ptr(); cimg_forXY(*this,x,y) *(buf2++) = (unsigned char)*(ptr_g++); } break; case 2: case 3: { // RGB images unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=3)]; const T *ptr_r = ptr(0,0,0,0), *ptr_g = ptr(0,0,0,1), *ptr_b = ptr(0,0,0,dim>2?2:0); colortype = JCS_RGB; cimg_forXY(*this,x,y) { *(buf2++) = (unsigned char)*(ptr_r++); *(buf2++) = (unsigned char)*(ptr_g++); *(buf2++) = (unsigned char)*(ptr_b++); } } break; default: { // YCMYK images unsigned char *buf2 = buf = new unsigned char[width*height*(dimbuf=4)]; 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); colortype = JCS_CMYK; cimg_forXY(*this,x,y) { *(buf2++) = (unsigned char)*(ptr_r++); *(buf2++) = (unsigned char)*(ptr_g++); *(buf2++) = (unsigned char)*(ptr_b++); *(buf2++) = (unsigned char)*(ptr_a++); } } break; } // Call libjpeg functions struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); jpeg_stdio_dest(&cinfo,nfile); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = dimbuf; cinfo.in_color_space = colortype; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE); jpeg_start_compress(&cinfo,TRUE); const unsigned int row_stride = width*dimbuf; JSAMPROW row_pointer[1]; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &buf[cinfo.next_scanline*row_stride]; jpeg_write_scanlines(&cinfo,row_pointer,1); } jpeg_finish_compress(&cinfo); delete[] buf; if (!file) cimg::fclose(nfile); jpeg_destroy_compress(&cinfo); return *this; #endif } //! Save a file in JPEG format. const CImg& save_jpeg(const char *const filename, const unsigned int quality=100) const { return save_jpeg(0,filename,quality); } //! Save the image using built-in ImageMagick++ library const CImg& save_magick(const char *const filename) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data); if (!filename) throw CImgArgumentException("CImg<%s>::save_magick() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); #ifdef cimg_use_magick Magick::Image image(Magick::Geometry(width,height),"black"); image.type(Magick::TrueColorType); const T *rdata = ptr(0,0,0,0), *gdata = dim>1?ptr(0,0,0,1):rdata, *bdata = dim>2?ptr(0,0,0,2):gdata; cimg_forXY(*this,x,y) image.pixelColor(x,y,Magick::ColorRGB(*(rdata++)/255.0,*(gdata++)/255.0,*(bdata++)/255.0)); image.syncPixels(); image.write(filename); #else throw CImgIOException("CImg<%s>::save_magick() : File '%s', Magick++ library has not been linked.", pixel_type(),filename); #endif return *this; } //! Save the image as a RGBA file const CImg& save_rgba(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(dim!=4, "CImg<%s>::save_rgba() : Instance image (%u,%u,%u,%u,%p) has not exactly 4 channels (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const unsigned int wh = width*height; unsigned char *buffer = new unsigned char[4*wh], *nbuffer=buffer; const T *ptr1 = ptr(0,0,0,0), *ptr2 = dim>1?ptr(0,0,0,1):ptr1, *ptr3 = dim>2?ptr(0,0,0,2):ptr1, *ptr4 = dim>3?ptr(0,0,0,3):0; for (unsigned int k=0; k::save_rgb() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p), specified file is (null).", pixel_type(),width,height,depth,dim,data); cimg::warn(dim!=3, "CImg<%s>::save_rgb() : Instance image (%u,%u,%u,%u,%p) has not exactly 3 channels (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); const unsigned int wh = width*height; unsigned char *buffer = new unsigned char[3*wh], *nbuffer=buffer; const T *ptr1 = ptr(0,0,0,0), *ptr2 = dim>1?ptr(0,0,0,1):ptr1, *ptr3 = dim>2?ptr(0,0,0,2):ptr1; for (unsigned int k=0; k res(40,38,1,3); if (first_time) { const unsigned char *ptrs = cimg::logo40x38; T *ptr1 = res.ptr(0,0,0,0), *ptr2 = res.ptr(0,0,0,1), *ptr3 = res.ptr(0,0,0,2); for (unsigned int off = 0; off const CImg& save_off(std::FILE *const file, const char *const filename, const CImgList& primitives, const CImgList& colors, const bool invert_faces=false) const { if (is_empty()) throw CImgInstanceException("CImg<%s>::save_off() : Instance image (%u,%u,%u,%u,%p) is empty (file '%s').", pixel_type(),width,height,depth,dim,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_off() : Specified filename is (null).",pixel_type()); if (height<3) return get_resize(-100,3,1,1,0).save_off(file,filename,primitives,colors,invert_faces); std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); std::fprintf(nfile,"OFF\n%u %u %u\n",width,primitives.size,3*primitives.size); cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n",(float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2))); cimglist_for(primitives,l) { const unsigned int prim = primitives[l].size(); const bool textured = (prim>4); const CImg& color = colors[l]; const unsigned int s = textured?color.dimv():color.size(); const float r = textured?(s>0?(float)(CImgStats(color.get_shared_channel(0),false).mean/255.0f):1.0f):(s>0?(float)(color(0)/255.0f):1.0f), g = textured?(s>1?(float)(CImgStats(color.get_shared_channel(1),false).mean/255.0f):r) :(s>1?(float)(color(1)/255.0f):r), b = textured?(s>2?(float)(CImgStats(color.get_shared_channel(2),false).mean/255.0f):r) :(s>2?(float)(color(2)/255.0f):r); switch (prim) { case 1: std::fprintf(nfile,"1 %u %f %f %f\n",(unsigned int)primitives(l,0),r,g,b); break; case 2: case 6: std::fprintf(nfile,"2 %u %u %f %f %f\n",(unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; case 3: case 9: if (invert_faces) 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); else 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); break; case 4: case 12: if (invert_faces) std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),(unsigned int)primitives(l,2),(unsigned int)primitives(l,3),r,g,b); else std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", (unsigned int)primitives(l,0),(unsigned int)primitives(l,3),(unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break; } } if (!file) cimg::fclose(nfile); return *this; } //! Save OFF files (GeomView 3D object files) template const CImg& save_off(const char *const filename, const CImgList& primitives, const CImgList& colors, const bool invert_faces=false) const { return save_off(0,filename,primitives,colors,invert_faces); } }; /* #----------------------------------------- # # # # Definition of the CImgList<> structure # # # #------------------------------------------ */ //! Class representing list of images CImg. template struct CImgList { //! Size of the list (number of elements inside) unsigned int size; //! Allocation size of the list unsigned int allocsize; //! Pointer to the first list element CImg *data; //! Define a CImgList::iterator typedef CImg* iterator; //! Define a CImgList::const_iterator typedef const CImg* const_iterator; //! Get value type typedef T value_type; //@} //--------------------------- // //! \name Plugins //@{ //--------------------------- #ifdef cimglist_plugin #include cimglist_plugin #endif //@} //------------------------------------------ // //! \name Constructors - Destructor - Copy //@{ //------------------------------------------ //! Default constructor CImgList(): size(0),allocsize(0),data(0) {} //! Destructor ~CImgList() { if (data) delete[] data; } //! In-place version of the default constructor and default destructor CImgList& assign() { if (data) delete[] data; size = allocsize = 0; data = 0; return *this; } //! Equivalent to assign() (STL-compliant name) CImgList& clear() { return assign(); } //! Copy constructor template CImgList(const CImgList& list): size(0),allocsize(0),data(0) { assign(list); } CImgList(const CImgList& list): size(0),allocsize(0),data(0) { assign(list); } //! Copy constructor that create a shared object template CImgList(const CImgList& list, const bool shared): size(0),allocsize(0),data(0) { assign(list,shared); } CImgList(const CImgList& list, const bool shared): size(0),allocsize(0),data(0) { assign(list,shared); } //! In-place version of the copy constructor template CImgList& assign(const CImgList& list, const bool shared=false) { assign(list.size); cimglist_for(*this,l) (*this)[l].assign(list[l],shared); return *this; } //! Construct an image list containing n empty images explicit CImgList(const unsigned int n): size(n) { data = new CImg[allocsize=cimg::nearest_pow2(n)]; } //! In-place version of the previous constructor CImgList& assign(const unsigned int n) { if (n) { if (allocsize(n<<2)) { if (data) delete[] data; data = new CImg[allocsize=cimg::nearest_pow2(n)]; } size = n; } else return assign(); return *this; } //! Construct an image list containing n images with specified size CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int dim=1): size(0),allocsize(0),data(0) { assign(n,width,height,depth,dim); } //! In-place version of the previous constructor CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height=1, const unsigned int depth=1, const unsigned int dim=1) { const unsigned int siz = width*height*depth*dim; if (n && siz) { assign(n); cimglist_for(*this,l) data[l].assign(width,height,depth,dim); } else return assign(); return *this; } //! Construct an image list containing n images with specified size, filled with val CImgList(const unsigned int n, const unsigned int width, const unsigned int height, const unsigned int depth, const unsigned int dim, const T& val): size(0),allocsize(0),data(0) { assign(n,width,height,depth,dim,val); } //! In-place version of the previous constructor CImgList& assign(const unsigned int n,const unsigned int width,const unsigned int height, const unsigned int depth, const unsigned int dim,const T& val) { assign(n,width,height,depth,dim); cimglist_for(*this,l) data[l].fill(val); return *this; } //! Construct a list containing n copies of the image img template CImgList(const unsigned int n, const CImg& img, const bool shared=false): size(0),allocsize(0),data(0) { assign(n,img,shared); } //! In-place version of the previous constructor template CImgList& assign(const unsigned int n, const CImg& img, const bool shared=false) { assign(n); cimglist_for(*this,l) data[l].assign(img,shared); return *this; } //! Construct an image list from one image template explicit CImgList(const CImg& img, const bool shared=false): size(0),allocsize(0),data(0) { assign(img,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img, const bool shared=false) { return assign(1,img,shared); } //! Construct an image list from two images template CImgList(const CImg& img1, const CImg& img2, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const bool shared=false) { assign(2); data[0].assign(img1,shared); data[1].assign(img2,shared); return *this; } //! Construct an image list from three images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const bool shared=false) { assign(3); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); return *this; } //! Construct an image list from four images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const bool shared=false) { assign(4); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); return *this; } //! Construct an image list from five images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const bool shared=false) { assign(5); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); return *this; } //! Construct an image list from six images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,img6,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const bool shared=false) { assign(6); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); data[5].assign(img6,shared); return *this; } //! Construct an image list from seven images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,img6,img7,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const bool shared=false) { assign(7); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); return *this; } //! Construct an image list from eight images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,img6,img7,img8,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const bool shared=false) { assign(8); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared); return *this; } //! Construct an image list from nine images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const CImg& img9, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,img6,img7,img8,img9,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const CImg& img9, const bool shared=false) { assign(9); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared); data[8].assign(img9,shared); return *this; } //! Construct an image list from ten images template CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const CImg& img9, const CImg& img10, const bool shared=false): size(0),allocsize(0),data(0) { assign(img1,img2,img3,img4,img5,img6,img7,img8,img9,img10,shared); } //! In-place version of the previous constructor template CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, const CImg& img9, const CImg& img10, const bool shared=false) { assign(10); data[0].assign(img1,shared); data[1].assign(img2,shared); data[2].assign(img3,shared); data[3].assign(img4,shared); data[4].assign(img5,shared); data[5].assign(img6,shared); data[6].assign(img7,shared); data[7].assign(img8,shared); data[8].assign(img9,shared); data[9].assign(img10,shared); return *this; } //! Construct an image list from a filename CImgList(const char *const filename): size(0),allocsize(0),data(0) { assign(filename); } //! In-place version of the previous constructor CImgList& assign(const char *const filename) { return load(filename); } //! Return a string describing the type of the image pixels in the list (template parameter \p T). static const char* pixel_type() { return cimg::type::id(); } //! Return \p true if list is empty bool is_empty() const { return (!data || !size); } operator bool() const { return !is_empty(); } //! Return \c true if the list contains an image with indice k bool contains(const int k) const { return data && k<(int)size; } //! Return \c true if the k-th image of the list contains the pixel (x,y,z,v) bool contains(const int k, const int x, const int y=0, const int z=0, const int v=0) const { return contains(k) && data[k].contains(x,y,z,v); } //@} //------------------------------ // //! \name Arithmetics Operators //@{ //------------------------------ //! Assignment operator template CImgList& operator=(const CImgList& list) { return assign(list); } CImgList& operator=(const CImgList& list) { return assign(list); } //! Assignment operator. template CImgList& operator=(const CImg& img) { cimglist_for(*this,l) data[l]=img; return *this; } //! Assignment operator. CImgList& operator=(const T& val) { cimglist_for(*this,l) data[l].fill(val); return *this; } //! Operator+ CImgList operator+() const { return CImgList(*this); } //! Operator+= #ifdef cimg_use_visualcpp6 CImgList& operator+=(const T& val) { #else template CImgList& operator+=(const t& val) { #endif cimglist_for(*this,l) (*this)[l]+=val; return *this; } //! Operator+= template CImgList& operator+=(const CImgList& list) { const unsigned int sizemax = min(size,list.size); for (unsigned int l=0; l res(size); cimglist_for(res,l) res[l].assign(-data[l]); return res; } //! Operator-=. #ifdef cimg_use_visualcpp6 CImgList& operator-=(const T& val) { #else template CImgList& operator-=(const t& val) { #endif cimglist_for(*this,l) (*this)[l]-=val; return *this; } //! Operator-=. template CImgList& operator-=(const CImgList& list) { const unsigned int sizemax = min(size,list.size); for (unsigned int l=0; l CImgList& operator*=(const t& val) { #endif cimglist_for(*this,l) (*this)[l]*=val; return *this; } //! Operator*=. template CImgList& operator*=(const CImgList& list) { const unsigned int N = cimg::min(size,list.size); for (unsigned int l=0; l CImgList& operator/=(const t& val) { #endif cimglist_for(*this,l) (*this)[l]/=val; return *this; } //! Operator/=. template CImgList& operator/=(const CImgList& list) { const unsigned int N = cimg::min(size,list.size); for (unsigned int l=0; l& operator[](const unsigned int pos) { #if cimg_debug>=3 if (pos>=size) { cimg::warn(true,"CImgList<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size); return *data; } #endif return data[pos]; } const CImg& operator[](const unsigned int pos) const { #if cimg_debug>=3 if (pos>=size) { cimg::warn(true,"CImgList<%s>::operator[] : bad list position %u, in a list of %u images",pixel_type(),pos,size); return *data; } #endif return data[pos]; } //! Equivalent to CImgList::operator[] CImg& operator()(const unsigned int pos) { return (*this)[pos]; } const CImg& operator()(const unsigned int pos) const { return (*this)[pos]; } //! Return a reference to (x,y,z,v) pixel of the pos-th image of the list T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) { return (*this)[pos](x,y,z,v); } const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int v=0) const { return (*this)[pos](x,y,z,v); } //! Equivalent to CImgList::operator[], with boundary checking CImg& at(const unsigned int pos) { if (pos>=size) throw CImgArgumentException("CImgList<%s>::at() : bad list position %u, in a list of %u images", pixel_type(),pos,size); return data[pos]; } const CImg& at(const unsigned int pos) const { if (pos>=size) throw CImgArgumentException("CImgList<%s>::at() : bad list position %u, in a list of %u images", pixel_type(),pos,size); return data[pos]; } //! Returns a reference to last element CImg& back() { return (*this)(size-1); } const CImg& back() const { return (*this)(size-1); } //! Returns a reference to the first element CImg& front() { return *data; } const CImg& front() const { return *data; } //! Returns an iterator to the beginning of the vector. iterator begin() { return data; } const_iterator begin() const { return data; } //! Returns an iterator just past the last element. iterator end() { return data + size; } const_iterator end() const { return data + size; } //! Insert a copy of the image \p img into the current image list, at position \p pos. template CImgList& insert(const CImg& img, const unsigned int pos, const bool shared) { if (pos>size) throw CImgArgumentException("CImgList<%s>::insert() : Cannot insert at position %u into a list with %u elements", pixel_type(),pos,size); if (shared) throw CImgArgumentException("CImgList<%s>::insert(): Cannot insert a shared image CImg<%s> into a CImgList<%s>", pixel_type(),img.pixel_type(),pixel_type()); CImg *new_data = (++size>allocsize)?new CImg[allocsize?(allocsize<<=1):(allocsize=1)]:0; if (!size || !data) { data = new_data; *data = img; } else { if (new_data) { if (pos) std::memcpy(new_data,data,sizeof(CImg)*pos); if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); std::memset(data,0,sizeof(CImg)*(size-1)); delete[] data; data = new_data; } else if (pos!=size-1) std::memmove(data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); data[pos].width = data[pos].height = data[pos].depth = data[pos].dim = 0; data[pos].data = 0; data[pos] = img; } return *this; } CImgList& insert(const CImg& img, const unsigned int pos, const bool shared) { if (pos>size) throw CImgArgumentException("CImgList<%s>::insert() : Can't insert at position %u into a list with %u elements", pixel_type(),pos,size); CImg *new_data = (++size>allocsize)?new CImg[allocsize?(allocsize<<=1):(allocsize=1)]:0; if (!size || !data) { data = new_data; if (shared && img) { data->width = img.width; data->height = img.height; data->depth = img.depth; data->dim = img.dim; data->is_shared = true; data->data = img.data; } else *data = img; } else { if (new_data) { if (pos) std::memcpy(new_data,data,sizeof(CImg)*pos); if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); if (shared && img) { new_data[pos].width = img.width; new_data[pos].height = img.height; new_data[pos].depth = img.depth; new_data[pos].dim = img.dim; new_data[pos].is_shared = true; new_data[pos].data = img.data; } else { new_data[pos].width = new_data[pos].height = new_data[pos].depth = new_data[pos].dim = 0; new_data[pos].data = 0; new_data[pos] = img; } std::memset(data,0,sizeof(CImg)*(size-1)); delete[] data; data = new_data; } else { if (pos!=size-1) std::memmove(data+pos+1,data+pos,sizeof(CImg)*(size-1-pos)); if (shared && img) { data[pos].width = img.width; data[pos].height = img.height; data[pos].depth = img.depth; data[pos].dim = img.dim; data[pos].is_shared = true; data[pos].data = img.data; } else { data[pos].width = data[pos].height = data[pos].depth = data[pos].dim = 0; data[pos].data = 0; data[pos] = img; } } } return *this; } template CImgList& insert(const CImg& img, const unsigned int pos) { return insert(img,pos,false); } template CImgList::type> get_insert(const CImg& img, const unsigned int pos, const bool shared=false) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(img,pos,shared); } //! Insert a copy of the image \p img at the current image list. template CImgList& insert(const CImg& img) { return insert(img,size); } template CImgList::type> get_insert(const CImg& img) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(img); } //! Insert a copy of the image \p img at the current image list. CImgList& operator<<(const CImg& img) { return insert(img); } //! Insert n copies of the image \p img into the current image list, at position \p pos. template CImgList& insert(const unsigned int n, const CImg& img, const unsigned int pos) { insert(img,pos); for (unsigned int i=1; i CImgList::type> get_insert(const unsigned int n, const CImg& img, const unsigned int pos) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(n,img,pos); } //! Insert n copies of the image \p img at the end of the list. template CImgList& insert(const unsigned int n, const CImg& img) { return insert(n,img,size); } template CImgList::type> get_insert(const unsigned int n, const CImg& img) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(n,img); } //! Insert a copy of the image list \p list into the current image list, starting from position \p pos. template CImgList& insert(const CImgList& list, const unsigned int pos) { cimglist_for(list,l) insert(list[l],pos+l); return *this; } CImgList& insert(const CImgList& list, const unsigned int pos) { if (this!=&list) cimglist_for(list,l) insert(list[l],pos+l); else insert(CImgList(list),pos); return *this; } template CImgList::type> get_insert(const CImgList& list, const unsigned int pos) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(list,pos); } //! Append a copy of the image list \p list at the current image list. template CImgList& insert(const CImgList& list) { return insert(list,size); } template CImgList::type> get_insert(const CImgList& list) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(list); } //! Insert a copy of the image list \p list at the current image list. CImgList& operator<<(const CImgList& list) { return insert(list); } //! Insert n copies of the list \p list at position \p pos of the current list. template CImgList& insert(const unsigned int n, const CImgList& list, const unsigned int pos) { for (unsigned int i=0; i CImgList::type> get_insert(const unsigned int n, const CImgList& list, const unsigned int pos) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(n,list,pos); } //! Insert n copies of the list at the end of the current list template CImgList& insert(const unsigned int n, const CImgList& list) { for (unsigned int i=0; i CImgList::type> get_insert(const unsigned int n, const CImgList& list) const { typedef typename cimg::largest::type restype; return CImgList(*this).insert(n,list); } //! Insert image \p img at the end of the list. template CImgList& push_back(const CImg& img) { return insert(img); } //! Insert image \p img at the front of the list. template CImgList& push_front(const CImg& img) { return insert(img,0); } //! Insert list \p list at the end of the current list. template CImgList& push_back(const CImgList& list) { return insert(list); } //! Insert list \p list at the front of the current list. template CImgList& push_front(const CImgList& list) { return insert(list,0); } //! Insert a shared copy of the image \p img into the current image list, at position \p pos. template CImgList& insert_shared(const CImg& img, const unsigned int pos) { return insert(img,pos,true); } template CImgList get_insert_shared(const CImg& img, const unsigned int pos) const { return CImgList(*this).insert_shared(img,pos); } //! Insert a shared copy of the image \p img at the current image list. template CImgList& insert_shared(const CImg& img) { return insert_shared(img,size); } template CImgList get_insert_shared(const CImg& img) const { return CImgList(*this).insert_shared(img); } //! Insert n shared copies of the image \p img into the current image list, at position \p pos. template CImgList& insert_shared(const unsigned int n, const CImg& img, const unsigned int pos) { insert_shared(img,pos); for (unsigned int i=1; i CImgList get_insert_shared(const unsigned int n, const CImg& img, const unsigned int pos) const { return CImgList(*this).insert_shared(n,img,pos); } //! Insert n shared copies of the image \p img at the end of the list. template CImgList& insert_shared(const unsigned int n, const CImg& img) { return insert_shared(n,img,size); } template CImgList get_insert_shared(const unsigned int n, const CImg& img) const { return CImgList(*this).insert_shared(n,img); } //! Insert a shared copy of all image of the list \p list into the current image list, starting from position \p pos. template CImgList& insert_shared(const CImgList& list, const unsigned int pos) { if (this!=&list) cimglist_for(list,l) insert_shared(list[l],pos+l); else insert_shared(CImgList(list),pos); return *this; } template CImgList get_insert_shared(const CImgList& list, const unsigned int pos) const { return CImgList(*this).insert_shared(list,pos); } //! Append a shared copy of the image list \p list at the current image list. template CImgList& insert_shared(const CImgList& list) { return insert_shared(list,size); } template CImgList get_insert_shared(const CImgList& list) const { return CImgList(*this).insert_shared(list); } //! Insert n shared copies of the list \p list at position \p pos of the current list. template CImgList& insert_shared(const unsigned int n, const CImgList& list, const unsigned int pos) { for (unsigned int i=0; i CImgList get_insert_shared(const unsigned int n, const CImgList& list, const unsigned int pos) const { return CImgList(*this).insert_shared(n,list,pos); } //! Insert n shared copies of the list \p list at the end of the list template CImgList& insert_shared(const unsigned int n, const CImgList& list) { return insert_shared(n,list,size); } template CImgList get_insert_shared(const unsigned int n, const CImgList& list) const { return CImgList(*this).insert_shared(n,list); } //! Remove the image at position \p pos from the image list. CImgList& remove(const unsigned int pos) { if (pos>=size) cimg::warn(true,"CImgList<%s>::remove() : Cannot remove an image from a list (%p,%u), at position %u.", pixel_type(),data,size,pos); else { data[pos].assign(); if (!(--size)) return assign(); if (size<8 || size>(allocsize>>2)) { // Removing item without reallocation. if (pos!=size) { std::memmove(data+pos,data+pos+1,sizeof(CImg)*(size-pos)); CImg &tmp = data[size]; tmp.width = tmp.height = tmp.depth = tmp.dim = 0; tmp.data = 0; } } else { // Removing item with reallocation. allocsize>>=2; CImg *new_data = new CImg[allocsize]; if (pos) std::memcpy(new_data,data,sizeof(CImg)*pos); if (pos!=size) std::memcpy(new_data+pos,data+pos+1,sizeof(CImg)*(size-pos)); std::memset(data,0,sizeof(CImg)*(size+1)); delete[] data; data = new_data; } } return *this; } CImgList get_remove(const unsigned int pos) const { return CImgList(*this).remove(pos); } //! Remove last element of the list; CImgList& pop_back() { return remove(size-1); } //! Remove last element of the list; CImgList& operator>>(CImg& img) { if (size) { img.swap((*this)[size-1]); return remove(size-1); } cimg::warn(true,"CImgList<%s>::operator>>() : List is empty",pixel_type()); img.assign(); return *this; } //! Remove first element of the list; CImgList& pop_front() { return remove(0); } //! Remove the element pointed by iterator \p iter; CImgList& erase(const iterator iter) { return remove(iter-data); } //! Remove the last image from the image list. CImgList& remove() { if (size) return remove(size-1); else cimg::warn(true,"CImgList<%s>::remove() : List is empty",pixel_type()); return *this; } CImgList get_remove() const { return CImgList(*this).remove(); } //! Reverse list order CImgList& reverse() { for (unsigned int l=0; l(*this).reverse(); } //! Get a sub-list CImgList get_crop(const unsigned int i0, const unsigned int i1, const bool shared=false) const { if (i0>i1 || i1>=size) throw CImgArgumentException("CImgList<%s>::crop() : Cannot crop a sub-list (%u->%u) from a list (%u,%p)", pixel_type(),i0,i1,size,data); CImgList res(i1-i0+1); cimglist_for(res,l) res[l].assign((*this)[i0+l],shared); return res; } //! Replace a list by its sublist CImgList& crop(const unsigned int i0, const unsigned int i1, const bool shared=false) { return get_crop(i0,i1,shared).swap(*this); } //@} //---------------------------- // //! \name Fourier Transforms //@{ //---------------------------- //! Compute the Fast Fourier Transform (along the specified axis). CImgList& FFT(const char axe, const bool inverse=false) { if (is_empty()) throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",pixel_type(),size,data); if (!data[0]) throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) is empty", pixel_type(),data[0].width,data[0].height,data[0].depth,data[0].dim,data[0].data); cimg::warn(size>2,"CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",pixel_type(),size,data); if (size==1) insert(CImg(data[0].width,data[0].height,data[0].depth,data[0].dim,0)); CImg &Ir = data[0], &Ii = data[1]; if (Ir.width!=Ii.width || Ir.height!=Ii.height || Ir.depth!=Ii.depth || Ir.dim!=Ii.dim) throw CImgInstanceException("CImgList<%s>::FFT() : Real part (%u,%u,%u,%u,%p) and imaginary part (%u,%u,%u,%u,%p)" "have different dimensions",pixel_type(), Ir.width,Ir.height,Ir.depth,Ir.dim,Ir.data,Ii.width,Ii.height,Ii.depth,Ii.dim,Ii.data); #ifdef cimg_use_fftw3 fftw_complex *data_in; fftw_plan data_plan; switch (cimg::uncase(axe)) { case 'x': { data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width); data_plan = fftw_plan_dft_1d(Ir.width, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE); cimg_forYZV(Ir,y,z,k) { T *ptrr = Ir.ptr(0,y,z,k), *ptri = Ii.ptr(0,y,z,k); double *ptrd = (double*)data_in; cimg_forX(Ir,x) { *(ptrd++) = (double)*(ptrr++); *(ptrd++) = (double)*(ptri++); } fftw_execute(data_plan); cimg_forX(Ir,x) { *(--ptri) = (T)*(--ptrd); *(--ptrr) = (T)*(--ptrd); } } } break; case 'y': { data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.height); data_plan = fftw_plan_dft_1d(Ir.height, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE); const unsigned int off = Ir.width; cimg_forXZV(Ir,x,z,k) { T *ptrr = Ir.ptr(x,0,z,k), *ptri = Ii.ptr(x,0,z,k); double *ptrd = (double*)data_in; cimg_forY(Ir,y) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } fftw_execute(data_plan); cimg_forY(Ir,y) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } } } break; case 'z': { data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.depth); data_plan = fftw_plan_dft_1d(Ir.depth, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE); const unsigned int off = Ir.width*Ir.height; cimg_forXYV(Ir,x,y,k) { T *ptrr = Ir.ptr(x,y,0,k), *ptri = Ii.ptr(x,y,0,k); double *ptrd = (double*)data_in; cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } fftw_execute(data_plan); cimg_forZ(Ir,z) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } } } break; case 'v': { data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.dim); data_plan = fftw_plan_dft_1d(Ir.dim, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE); const unsigned int off = Ir.width*Ir.height*Ir.depth; cimg_forXYZ(Ir,x,y,z) { T *ptrr = Ir.ptr(x,y,z,0), *ptri = Ii.ptr(x,y,z,0); double *ptrd = (double*)data_in; cimg_forV(Ir,k) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=off; ptri+=off; } fftw_execute(data_plan); cimg_forV(Ir,k) { ptrr-=off; ptri-=off; *ptri = (T)*(--ptrd); *ptrr = (T)*(--ptrd); } } } break; } fftw_destroy_plan(data_plan); fftw_free(data_in); #else switch (cimg::uncase(axe)) { case 'x': { // Fourier along X const unsigned int N = Ir.width, N2 = (N>>1); if (((N-1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image along 'x' is %d != 2^N", pixel_type(),N); for (unsigned int i=0,j=0; ii) 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)); if (j=m; j-=m, m=n, n>>=1); } for (unsigned int delta=2; delta<=N; delta<<=1) { const unsigned int delta2 = (delta>>1); for (unsigned int i=0; i>1); if (((N-1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'y' is %d != 2^N", pixel_type(),N); for (unsigned int i=0,j=0; ii) 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)); if (j=m; j-=m, m=n, n>>=1); } for (unsigned int delta=2; delta<=N; delta<<=1) { const unsigned int delta2 = (delta>>1); for (unsigned int i=0; i>1); if (((N-1)&N) && N!=1) throw CImgInstanceException("CImgList<%s>::FFT() : Dimension of instance image(s) along 'z' is %d != 2^N", pixel_type(),N); for (unsigned int i=0,j=0; ii) 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)); if (j=m; j-=m, m=n, n>>=1); } for (unsigned int delta=2; delta<=N; delta<<=1) { const unsigned int delta2 = (delta>>1); for (unsigned int i=0; i::FFT() : unknown axe '%c', must be 'x','y' or 'z'"); } #endif return *this; } //! Return the Fast Fourier Transform of a complex image (along a specified axis). CImgList::type> get_FFT(const char axe, const bool inverse=false) const { typedef typename cimg::largest::type restype; return CImgList(*this).FFT(axe,inverse); } //! Compute the Fast Fourier Transform of a complex image. CImgList& FFT(const bool inverse=false) { if (is_empty()) throw CImgInstanceException("CImgList<%s>::FFT() : Instance list (%u,%p) is empty",pixel_type(),size,data); cimg::warn(size>2,"CImgList<%s>::FFT() : Instance list (%u,%p) have more than 2 images",pixel_type(),size,data); if (size==1) insert(CImg(data[0].width,data[0].height,data[0].depth,data[0].dim,0)); CImg &Ir = data[0]; #ifdef cimg_use_fftw3 CImg &Ii = data[1]; fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * Ir.width*Ir.height*Ir.depth); fftw_plan data_plan; const unsigned int w = Ir.width, wh = w*Ir.height, whd = wh*Ir.depth; data_plan = fftw_plan_dft_3d(Ir.width, Ir.height, Ir.depth, data_in, data_in, inverse?FFTW_BACKWARD:FFTW_FORWARD, FFTW_ESTIMATE); cimg_forV(Ir,k) { T *ptrr = Ir.ptr(0,0,0,k), *ptri = Ii.ptr(0,0,0,k); double *ptrd = (double*)data_in; cimg_forX(Ir,x) { cimg_forY(Ir,y) { cimg_forZ(Ir,z) { *(ptrd++) = (double)*ptrr; *(ptrd++) = (double)*ptri; ptrr+=wh; ptri+=wh; } ptrr-=whd-w; ptri-=whd-w; } ptrr-=wh-1; ptri-=wh-1; } fftw_execute(data_plan); ptrd = (double*)data_in; ptrr = Ir.ptr(0,0,0,k), ptri = Ii.ptr(0,0,0,k); cimg_forX(Ir,x) { cimg_forY(Ir,y) { cimg_forZ(Ir,z) { *ptrr = (T)*(ptrd++); *ptri = (T)*(ptrd++); ptrr+=wh; ptri+=wh; } ptrr-=whd-w; ptri-=whd-w; } ptrr-=wh-1; ptri-=wh-1; } } fftw_destroy_plan(data_plan); fftw_free(data_in); #else if (Ir.depth>1) FFT('z',inverse); if (Ir.height>1) FFT('y',inverse); if (Ir.width>1) FFT('x',inverse); #endif return *this; } //! Return the Fast Fourier Transform of a complex image CImgList::type> get_FFT(const bool inverse=false) const { typedef typename cimg::largest::type restype; return CImgList(*this).FFT(inverse); } //@} //---------------------------------- // //! \name Input-Output and Display //@{ //---------------------------------- //! Print informations about the list on the standard output. const CImgList& print(const char* title=0, const unsigned int print_flag=1) const { char tmp[1024]; std::fprintf(stderr,"%-8s(this=%p) : { size=%u, data=%p }\n",title?title:"CImgList", (void*)this,size,(void*)data); switch (print_flag) { case 1: { cimglist_for(*this,l) if (l<4 || l>=size-4) { std::sprintf(tmp,"%s[%d]",title?title:"CImgList",l); data[l].print(tmp,print_flag); } else { if (l==4) std::fprintf(stderr,"...\n"); } } break; default: { cimglist_for(*this,l) { std::sprintf(tmp,"%s[%d]",title?title:"CImgList",l); data[l].print(tmp,print_flag); } } break; } return *this; } //! Display informations about the list on the standard output. const CImgList& print(const unsigned int print_flag) const { return print(0,print_flag); } //! Load an image list from a file. static CImgList get_load(const char *const filename) { const char *ext = cimg::filename_split(filename); if (!cimg::strncasecmp(ext,"cimg",4) || !ext[0]) return get_load_cimg(filename); if (!cimg::strncasecmp(ext,"rec",3) || !cimg::strncasecmp(ext,"par",3)) return get_load_parrec(filename); CImgList res(1); res[0].load(filename); return res; } //! In-place version of load(). CImgList& load(const char *const filename) { return get_load(filename).swap(*this); } #define cimg_load_cimg_case(Ts,Tss) \ if (!loaded && !cimg::strcasecmp(Ts,tmp2)) for (unsigned int l=0; l0) { \ Tss *buf = new Tss[w*h*z*k]; cimg::fread(buf,w*h*z*k,nfile); \ if (endian) cimg::endian_swap(buf,w*h*z*k); \ CImg idest(w,h,z,k); \ cimg_foroff(idest,off) idest[off] = (T)(buf[off]); idest.swap(res[l]); \ delete[] buf; \ } \ loaded = true; \ } //! Load an image list from a file (.raw format). static CImgList get_load_cimg(std::FILE *const file, const char *const filename=0) { typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); char tmp[256],tmp2[256]; int i; bool loaded = false; unsigned int n,j,w,h,z,k,err; j=0; while((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++]=i; tmp[j]='\0'; err=std::sscanf(tmp,"%u%*c%255[A-Za-z ]",&n,tmp2); if (err!=2) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', Unknow CImg RAW header.", pixel_type(),filename?filename:"(FILE*)"); } CImgList res(n); cimg_load_cimg_case("bool",bool); cimg_load_cimg_case("unsigned char",uchar); cimg_load_cimg_case("uchar",uchar); cimg_load_cimg_case("char",char); cimg_load_cimg_case("unsigned short",ushort); cimg_load_cimg_case("ushort",ushort); cimg_load_cimg_case("short",short); cimg_load_cimg_case("unsigned int",uint); cimg_load_cimg_case("uint",uint); cimg_load_cimg_case("int",int); cimg_load_cimg_case("unsigned long",ulong); cimg_load_cimg_case("ulong",ulong); cimg_load_cimg_case("long",long); cimg_load_cimg_case("float",float); cimg_load_cimg_case("double",double); if (!loaded) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImgList<%s>::load_cimg() : File '%s', cannot read images of pixels coded as '%s'.", pixel_type(),filename?filename:"(FILE*)",tmp2); } if (!file) cimg::fclose(nfile); return res; } //! Load an image list from a file (.raw format). static CImgList get_load_cimg(const char *const filename) { return get_load_cimg(0,filename); } //! In-place version of get_load_cimg(). CImgList& load_cimg(std::FILE *const file, const char *const filename=0) { return get_load_cimg(file,filename).swap(*this); } //! In-place version of get_load_cimg(). CImgList& load_cimg(const char *const filename) { return get_load_cimg(filename).swap(*this); } //! Load PAR-REC (Philips) image file static CImgList get_load_parrec(const char *const filename) { char body[1024], filenamepar[1024], filenamerec[1024]; const char *ext = cimg::filename_split(filename,body); if (!cimg::strncmp(ext,"par",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.rec",body); } if (!cimg::strncmp(ext,"PAR",3)) { std::strcpy(filenamepar,filename); std::sprintf(filenamerec,"%s.REC",body); } if (!cimg::strncmp(ext,"rec",3)) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.par",body); } if (!cimg::strncmp(ext,"REC",3)) { std::strcpy(filenamerec,filename); std::sprintf(filenamepar,"%s.PAR",body); } std::FILE *file = cimg::fopen(filenamepar,"r"); // Parse header file CImgList st_slices; CImgList st_global; int err; char line[256]={0}; do { err=std::fscanf(file,"%255[^\n]%*c",line); } while (err!=EOF && (line[0]=='#' || line[0]=='.')); do { unsigned int sn,sizex,sizey,pixsize; float rs,ri,ss; err=std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&sizex,&sizey,&ri,&rs,&ss); if (err==7) { st_slices.insert(CImg::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0)); unsigned int i; for (i=0; i::vector(sizex,sizey,sn)); else { CImg &vec = st_global[i]; if (sizex>vec[0]) vec[0] = sizex; if (sizey>vec[1]) vec[1] = sizey; vec[2] = sn; } st_slices[st_slices.size-1][7] = (float)i; } } while (err==7); // Read data std::FILE *file2 = cimg::fopen(filenamerec,"rb"); CImgList dest; { cimglist_for(st_global,l) { const CImg& vec = st_global[l]; dest.insert(CImg(vec[0],vec[1],vec[2])); }} cimglist_for(st_slices,l) { const CImg& vec = st_slices[l]; const unsigned int sn = (unsigned int)vec[0]-1, pixsize = (unsigned int)vec[1], sizex = (unsigned int)vec[2], sizey = (unsigned int)vec[3], imn = (unsigned int)vec[7]; const float ri = vec[4], rs = vec[5], ss = vec[6]; switch (pixsize) { case 8: { CImg buf(sizex,sizey); cimg::fread(buf.data,sizex*sizey,file2); if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); CImg& img = dest[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; case 16: { CImg buf(sizex,sizey); cimg::fread(buf.data,sizex*sizey,file2); if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); CImg& img = dest[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; case 32: { CImg buf(sizex,sizey); cimg::fread(buf.data,sizex*sizey,file2); if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); CImg& img = dest[imn]; cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); } break; default: cimg::fclose(file); cimg::fclose(file2); throw CImgIOException("CImg<%s>::load_parrec() : File '%s', cannot handle image with pixsize = %d bits.", pixel_type(),filename,pixsize); break; } } cimg::fclose(file); cimg::fclose(file2); if (!dest.size) throw CImgIOException("CImg<%s>::load_parrec() : File '%s' does not appear to be a valid PAR-REC file.", pixel_type(),filename); return dest; } //! In-place version of get_load_parrec(). CImgList& load_parrec(const char *const filename) { return get_load_parrec(filename).swap(*this); } //! Load YUV image sequence. static CImgList get_load_yuv(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb=false) { if (sizex%2 || sizey%2) throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', image dimensions along X and Y must be even numbers (given are %ux%u)\n", pixel_type(),filename?filename:"(unknown)",sizex,sizey); if (!sizex || !sizey) throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given image sequence size (%u,%u) is invalid", pixel_type(),filename?filename:"(unknown)",sizex,sizey); if (last_frame>0 && first_frame>(unsigned int)last_frame) throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given first frame %u is posterior to last frame %d.", pixel_type(),filename?filename:"(unknown)",first_frame,last_frame); if (!sizex || !sizey) throw CImgArgumentException("CImgList<%s>::load_yuv() : File '%s', given frame size (%u,%u) is invalid.", pixel_type(),filename?filename:"(unknown)",sizex,sizey); CImgList res; CImg tmp(sizex,sizey,1,3), UV(sizex/2,sizey/2,1,2); std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); bool stopflag = false; int err; if (first_frame) { err = std::fseek(nfile,first_frame*(sizex*sizey + sizex*sizey/2),SEEK_CUR); if (err) { if (!file) cimg::fclose(nfile); throw CImgIOException("CImgList<%s>::load_yuv() : File '%s' doesn't contain frame number %u " "(out of range error).",pixel_type(),filename?filename:"(FILE*)",first_frame); } } unsigned int frame; for (frame = first_frame; !stopflag && (last_frame<0 || frame<=(unsigned int)last_frame); frame++) { tmp.fill(0); // TRY to read the luminance, don't replace by cimg::fread ! err = (int)std::fread((void*)(tmp.ptr()),1,(size_t)(tmp.width*tmp.height),nfile); if (err!=(int)(tmp.width*tmp.height)) { stopflag = true; cimg::warn(err>0,"CImgList<%s>::load_yuv() : File '%s' contains incomplete data," " or given image dimensions (%u,%u) are incorrect.", pixel_type(),filename?filename:"(unknown)",sizex,sizey); } else { UV.fill(0); // TRY to read the luminance, don't replace by cimg::fread ! err = (int)std::fread((void*)(UV.ptr()),1,(size_t)(UV.size()),nfile); if (err!=(int)(UV.size())) { stopflag = true; cimg::warn(err>0,"CImgList<%s>::load_yuv() : File '%s' contains incomplete data," " or given image dimensions (%u,%u) are incorrect.", pixel_type(),filename?filename:"(unknown)",sizex,sizey); } else { cimg_forXY(UV,x,y) { const int x2=2*x, y2=2*y; tmp(x2,y2,1) = tmp(x2+1,y2,1) = tmp(x2,y2+1,1) = tmp(x2+1,y2+1,1) = UV(x,y,0); tmp(x2,y2,2) = tmp(x2+1,y2,2) = tmp(x2,y2+1,2) = tmp(x2+1,y2+1,2) = UV(x,y,1); } if (yuv2rgb) tmp.YCbCrtoRGB(); res.insert(tmp); } } } cimg::warn(stopflag && last_frame>=0 && frame!=(unsigned int)last_frame, "CImgList<%s>::load_yuv() : File '%s', frame %d not reached since only %u frames were found in the file.", pixel_type(),filename?filename:"(unknown)",last_frame,frame-1,filename); if (!file) cimg::fclose(nfile); return res; } //! Load YUV image sequence. static CImgList get_load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb=false) { return get_load_yuv(0,filename,sizex,sizey,first_frame,last_frame,yuv2rgb); } //! In-place version of get_load_yuv(). CImgList& load_yuv(std::FILE *const file, const char *const filename, const unsigned int sizex, const unsigned int sizey=1, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb=false) { return get_load_yuv(file,filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); } //! In-place version of get_load_yuv(). CImgList& load_yuv(const char *const filename, const unsigned int sizex, const unsigned int sizey, const unsigned int first_frame=0, const int last_frame=-1, const bool yuv2rgb=false) { return get_load_yuv(filename,sizex,sizey,first_frame,last_frame,yuv2rgb).swap(*this); } //! Load from OFF file format template static CImgList get_load_off(const char *const filename, CImgList& primitives, CImgList& colors, const bool invert_faces=false) { return CImg::get_load_off(filename,primitives,colors,invert_faces).get_split('x'); } //! In-place version of get_load_off() template CImgList& load_off(std::FILE *const file, const char *const filename, CImgList& primitives, CImgList& colors, const bool invert_faces=false) { return get_load_off(file,filename,primitives,colors,invert_faces).swap(*this); } //! In-place version of get_load_off() template CImgList& load_off(const char *const filename, CImgList& primitives, CImgList& colors, const bool invert_faces=false) { return get_load_off(filename,primitives,colors,invert_faces).swap(*this); } //! Save an image list into a file. /** Depending on the extension of the given filename, a file format is chosen for the output file. **/ const CImgList& save(const char *const filename) const { if (is_empty()) throw CImgInstanceException("CImgList<%s>::save() : Instance list (%u,%p) is empty (file '%s').", pixel_type(),size,data,filename); if (!filename) throw CImgArgumentException("CImg<%s>::save() : Instance list (%u,%p), specified filename is (null).", pixel_type(),size,data); const char *ext = cimg::filename_split(filename); if (!cimg::strncasecmp(ext,"cimg",4) || !ext[0]) return save_cimg(filename); if (!cimg::strncasecmp(ext,"yuv",3)) return save_yuv(filename,true); if (size==1) data[0].save(filename,-1); else cimglist_for(*this,l) data[l].save(filename,l); return *this; } //! Save an image sequence into a YUV file const CImgList& save_yuv(std::FILE *const file, const char *const filename=0, const bool rgb2yuv=true) const { if (is_empty()) throw CImgInstanceException("CImgList<%s>::save_yuv() : Instance list (%u,%p) is empty (file '%s').", pixel_type(),size,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_yuv() : Instance list (%u,%p), specified file is (null).", pixel_type(),size,data); if ((*this)[0].dimx()%2 || (*this)[0].dimy()%2) throw CImgInstanceException("CImgList<%s>::save_yuv() : Image dimensions must be even numbers (current are %ux%u, file '%s').", pixel_type(),(*this)[0].dimx(),(*this)[0].dimy(),filename?filename:"(unknown)"); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); cimglist_for(*this,l) { CImg YCbCr((*this)[l]); if (rgb2yuv) YCbCr.RGBtoYCbCr(); cimg::fwrite(YCbCr.ptr(),YCbCr.width*YCbCr.height,nfile); cimg::fwrite(YCbCr.get_resize(YCbCr.width/2, YCbCr.height/2,1,3,3).ptr(0,0,0,1), YCbCr.width*YCbCr.height/2,nfile); } if (!file) cimg::fclose(nfile); return *this; } //! Save an image sequence into a YUV file const CImgList& save_yuv(const char *const filename=0, const bool rgb2yuv=true) const { return save_yuv(0,filename,rgb2yuv); } //! Save an image list into a CImg file (RAW binary file + simple header) /** A CImg RAW file is a simple uncompressed binary file that may be used to save list of CImg images. \param filename : name of the output file. \return A reference to the current CImgList instance is returned. **/ const CImgList& save_cimg(std::FILE *const file, const char *const filename=0) const { if (is_empty()) throw CImgInstanceException("CImgList<%s>::save_cimg() : Instance list (%u,%p) is empty (file '%s').", pixel_type(),size,data,filename?filename:"(unknown)"); if (!file && !filename) throw CImgArgumentException("CImg<%s>::save_cimg() : Instance list (%u,%p), specified file is (null).", pixel_type(),size,data); std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); std::fprintf(nfile,"%u %s\n",size,pixel_type()); cimglist_for(*this,l) { const CImg& img = data[l]; std::fprintf(nfile,"%u %u %u %u\n",img.width,img.height,img.depth,img.dim); if (img.data) { if (cimg::endian()) { CImg tmp(img); cimg::endian_swap(tmp.data,tmp.size()); cimg::fwrite(tmp.data,img.width*img.height*img.depth*img.dim,nfile); } else cimg::fwrite(img.data,img.width*img.height*img.depth*img.dim,nfile); } } if (!file) cimg::fclose(nfile); return *this; } //! Save an image list into a CImg file (RAW binary file + simple header) const CImgList& save_cimg(const char *const filename) const { return save_cimg(0,filename); } //! Save an image list into a OFF file. template const CImgList& save_off(std::FILE *const file, const char *const filename, const CImgList& primitives, const CImgList& colors, const bool invert_faces=false) const { get_append('x','y').save_off(file,filename,primitives,colors,invert_faces); return *this; } //! Save an image list into a OFF file. template const CImgList& save_off(const char *const filename, const CImgList& primitives, const CImgList& colors, const bool invert_faces=false) const { return save_off(0,filename,primitives,colors,invert_faces); } //! Return a single image which is the concatenation of all images of the current CImgList instance. /** \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). \return A CImg image corresponding to the concatenation is returned. **/ CImg get_append(const char axe='x', const char align='c') const { if (is_empty()) return CImg(); unsigned int dx=0, dy=0, dz=0, dv=0, pos=0; CImg res; switch(cimg::uncase(axe)) { case 'x': { switch (cimg::uncase(align)) { case 'x': { dy = dz = dv = 1; cimglist_for(*this,l) dx+=(*this)[l].size(); } break; case 'y': { dx = size; dz = dv = 1; cimglist_for(*this,l) dy = cimg::max(dy,(unsigned int)(*this)[l].size()); } break; case 'z': { dx = size; dy = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break; case 'v': { dx = size; dy = dz = 1; cimglist_for(*this,l) dv = cimg::max(dz,(unsigned int)(*this)[l].size()); } break; default: cimglist_for(*this,l) { const CImg& img = (*this)[l]; dx += img.width; dy = cimg::max(dy,img.height); dz = cimg::max(dz,img.depth); dv = cimg::max(dv,img.dim); } } res.assign(dx,dy,dz,dv,0); switch (cimg::uncase(align)) { case 'x': { cimglist_for(*this,l) { res.draw_image(CImg((*this)[l],true).unroll('x'),pos,0,0,0); pos+=(*this)[l].size(); } } break; case 'y': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('y'),pos++,0,0,0); } break; case 'z': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('z'),pos++,0,0,0); } break; case 'v': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('v'),pos++,0,0,0); } break; case 'p': { cimglist_for(*this,l) { res.draw_image((*this)[l],pos,0,0,0); pos+=(*this)[l].width; } } break; case 'n': { cimglist_for(*this,l) { res.draw_image((*this)[l],pos,dy-(*this)[l].height,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].width; } } break; default : { cimglist_for(*this,l) { res.draw_image((*this)[l],pos,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2); pos+=(*this)[l].width; } } break; } } break; case 'y': { switch (cimg::uncase(align)) { case 'x': { dy = size; dz = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break; case 'y': { dx = dz = dv = 1; cimglist_for(*this,l) dy+=(*this)[l].size(); } break; case 'z': { dy = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dz,(unsigned int)(*this)[l].size()); } break; case 'v': { dy = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break; default: cimglist_for(*this,l) { const CImg& img = (*this)[l]; dx = cimg::max(dx,img.width); dy += img.height; dz = cimg::max(dz,img.depth); dv = cimg::max(dv,img.dim); } } res.assign(dx,dy,dz,dv,0); switch (cimg::uncase(align)) { case 'x': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('x'),0,pos++,0,0); } break; case 'y': { cimglist_for(*this,l) { res.draw_image(CImg((*this)[l],true).unroll('y'),0,pos,0,0); pos+=(*this)[l].size(); } } break; case 'z': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('z'),0,pos++,0,0); } break; case 'v': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('v'),0,pos++,0,0); } break; case 'p': { cimglist_for(*this,l) { res.draw_image((*this)[l],0,pos,0,0); pos+=(*this)[l].height; } } break; case 'n': { cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,pos,dz-(*this)[l].depth,dv-(*this)[l].dim); pos+=(*this)[l].height; } } break; default : { cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,pos,(dz-(*this)[l].depth)/2,(dv-(*this)[l].dim)/2); pos+=(*this)[l].height; } } break; } } break; case 'z': { switch (cimg::uncase(align)) { case 'x': { dz = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break; case 'y': { dz = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break; case 'z': { dx = dy = dv = 1; cimglist_for(*this,l) dz+=(*this)[l].size(); } break; case 'v': { dz = size; dx = dz = 1; cimglist_for(*this,l) dv = cimg::max(dv,(unsigned int)(*this)[l].size()); } break; default : cimglist_for(*this,l) { const CImg& img = (*this)[l]; dx = cimg::max(dx,img.width); dy = cimg::max(dy,img.height); dz += img.depth; dv = cimg::max(dv,img.dim); } } res.assign(dx,dy,dz,dv,0); switch (cimg::uncase(align)) { case 'x': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('x'),0,0,pos++,0); } break; case 'y': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('y'),0,0,pos++,0); } break; case 'z': { cimglist_for(*this,l) { res.draw_image(CImg((*this)[l],true).unroll('z'),0,0,pos,0); pos+=(*this)[l].size(); } } break; case 'v': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('v'),0,0,pos++,0); } break; case 'p': { cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,pos,0); pos+=(*this)[l].depth; } } break; case 'n': { cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,pos,dv-(*this)[l].dim); pos+=(*this)[l].depth; } } break; case 'c': { cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,pos,(dv-(*this)[l].dim)/2); pos+=(*this)[l].depth; } } break; } } break; case 'v': { switch (cimg::uncase(align)) { case 'x': { dv = size; dy = dv = 1; cimglist_for(*this,l) dx = cimg::max(dx,(unsigned int)(*this)[l].size()); } break; case 'y': { dv = size; dx = dv = 1; cimglist_for(*this,l) dy = cimg::max(dz,(unsigned int)(*this)[l].size()); } break; case 'z': { dv = size; dx = dv = 1; cimglist_for(*this,l) dz = cimg::max(dv,(unsigned int)(*this)[l].size()); } break; case 'v': { dx = dy = dz = 1; cimglist_for(*this,l) dv+=(*this)[l].size(); } break; default : cimglist_for(*this,l) { const CImg& img = (*this)[l]; dx = cimg::max(dx,img.width); dy = cimg::max(dy,img.height); dz = cimg::max(dz,img.depth); dv += img.dim; } } res.assign(dx,dy,dz,dv,0); switch (cimg::uncase(align)) { case 'x': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('x'),0,0,0,pos++); } break; case 'y': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('y'),0,0,0,pos++); } break; case 'z': { cimglist_for(*this,l) res.draw_image(CImg((*this)[l],true).unroll('v'),0,0,0,pos++); } break; case 'v': { cimglist_for(*this,l) { res.draw_image(CImg((*this)[l],true).unroll('z'),0,0,0,pos); pos+=(*this)[l].size(); } } break; case 'p': { cimglist_for(*this,l) { res.draw_image((*this)[l],0,0,0,pos); pos+=(*this)[l].dim; } } break; case 'n': { cimglist_for(*this,l) { res.draw_image((*this)[l],dx-(*this)[l].width,dy-(*this)[l].height,dz-(*this)[l].depth,pos); pos+=(*this)[l].dim; } } break; case 'c': { cimglist_for(*this,l) { res.draw_image((*this)[l],(dx-(*this)[l].width)/2,(dy-(*this)[l].height)/2,(dz-(*this)[l].depth)/2,pos); pos+=(*this)[l].dim; } } break; } } break; default: throw CImgArgumentException("CImgList<%s>::get_append() : unknow axe '%c', must be 'x','y','z' or 'v'",pixel_type(),axe); } return res; } // Create an auto-cropped font (along the X axis) from a input font \p font. CImgList get_crop_font() const { CImgList res; cimglist_for(*this,l) { const CImg& letter = (*this)[l]; int xmin = letter.width, xmax = 0; cimg_forXY(letter,x,y) if (letter(x,y)) { if (xxmax) xmax=x; } if (xmin>xmax) res.insert(CImg(letter.width,letter.height,1,letter.dim,0)); else res.insert(letter.get_crop(xmin,0,xmax,letter.height-1)); } res[' '].resize(res['f'].width); res[' '+256].resize(res['f'].width); return res; } CImgList& crop_font() { return get_crop_font().swap(*this); } static CImgList get_font(const unsigned int *const font,const unsigned int w,const unsigned int h, const unsigned int paddingx, const unsigned int paddingy, const bool variable_size=true) { CImgList res = CImgList(256,w,h,1,3).insert(CImgList(256,w,h,1,1)); const unsigned int *ptr = font; unsigned int m = 0, val = 0; for (unsigned int y=0; y>=1; if (!m) { m=0x80000000; val = *(ptr++); } CImg& img = res[x/w], &mask = res[x/w+256]; unsigned int xm = x%w; img(xm,y,0) = img(xm,y,1) = img(xm,y,2) = mask(xm,y,0) = (T)((val&m)?1:0); } if (variable_size) res.crop_font(); if (paddingx || paddingy) cimglist_for(res,l) res[l].resize(res[l].dimx()+paddingx, res[l].dimy()+paddingy,1,-100,0); return res; } //! Return a CImg pre-defined font with desired size /** \param font_height = height of the desired font (can be 11,13,24,38 or 57) \param fixed_size = tell if the font has a fixed or variable width. **/ static CImgList get_font(const unsigned int font_width, const bool variable_size=true) { if (font_width<=11) { static CImgList font7x11, nfont7x11; if (!variable_size && !font7x11) font7x11 = get_font(cimg::font7x11,7,11,1,0,false); if (variable_size && !nfont7x11) nfont7x11 = get_font(cimg::font7x11,7,11,1,0,true); return variable_size?nfont7x11:font7x11; } if (font_width<=13) { static CImgList font10x13, nfont10x13; if (!variable_size && !font10x13) font10x13 = get_font(cimg::font10x13,10,13,1,0,false); if (variable_size && !nfont10x13) nfont10x13 = get_font(cimg::font10x13,10,13,1,0,true); return variable_size?nfont10x13:font10x13; } if (font_width<=17) { static CImgList font8x17, nfont8x17; if (!variable_size && !font8x17) font8x17 = get_font(cimg::font8x17,8,17,1,0,false); if (variable_size && !nfont8x17) nfont8x17 = get_font(cimg::font8x17,8,17,1,0,true); return variable_size?nfont8x17:font8x17; } if (font_width<=19) { static CImgList font10x19, nfont10x19; if (!variable_size && !font10x19) font10x19 = get_font(cimg::font10x19,10,19,2,0,false); if (variable_size && !nfont10x19) nfont10x19 = get_font(cimg::font10x19,10,19,2,0,true); return variable_size?nfont10x19:font10x19; } if (font_width<=24) { static CImgList font12x24, nfont12x24; if (!variable_size && !font12x24) font12x24 = get_font(cimg::font12x24,12,24,2,0,false); if (variable_size && !nfont12x24) nfont12x24 = get_font(cimg::font12x24,12,24,2,0,true); return variable_size?nfont12x24:font12x24; } if (font_width<=32) { static CImgList font16x32, nfont16x32; if (!variable_size && !font16x32) font16x32 = get_font(cimg::font16x32,16,32,2,0,false); if (variable_size && !nfont16x32) nfont16x32 = get_font(cimg::font16x32,16,32,2,0,true); return variable_size?nfont16x32:font16x32; } if (font_width<=38) { static CImgList font19x38, nfont19x38; if (!variable_size && !font19x38) font19x38 = get_font(cimg::font19x38,19,38,3,0,false); if (variable_size && !nfont19x38) nfont19x38 = get_font(cimg::font19x38,19,38,3,0,true); return variable_size?nfont19x38:font19x38; } static CImgList font29x57, nfont29x57; if (!variable_size && !font29x57) font29x57 = get_font(cimg::font29x57,29,57,5,0,false); if (variable_size && !nfont29x57) nfont29x57 = get_font(cimg::font29x57,29,57,5,0,true); return variable_size?nfont29x57:font29x57; } //! Display the current CImgList instance in an existing CImgDisplay window (by reference). /** This function displays the list images of the current CImgList instance into an existing CImgDisplay window. Images of the list are concatenated in a single temporarly image for visualization purposes. The function returns immediately. \param disp : reference to an existing CImgDisplay instance, where the current image list will be displayed. \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). \return A reference to the current CImgList instance is returned. **/ const CImgList& display(CImgDisplay& disp, const char axe='x', const char align='c') const { get_append(axe,align).display(disp); return *this; } //! Display the current CImgList instance in a new display window. /** This function opens a new window with a specific title and displays the list images of the current CImgList instance into it. Images of the list are concatenated in a single temporarly image for visualization purposes. The function returns when a key is pressed or the display window is closed by the user. \param title : specify the title of the opening display window. \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). \param min_size : specify the minimum size of the opening display window. Images having dimensions below this size will be upscaled. \param max_size : specify the maximum size of the opening display window. Images having dimensions above this size will be downscaled. \return A reference to the current CImgList instance is returned. **/ const CImgList& display(const char* title, const char axe='x', const char align='c', const int min_size=128, const int max_size=1024) const { if (is_empty()) throw CImgInstanceException("CImgList<%s>::display() : Instance list (%u,%u) is empty.", pixel_type(),size,data); const CImg visu = get_append(axe,align); CImgDisplay *disp; unsigned int w = visu.width+(visu.depth>1?visu.depth:0), h = visu.height+(visu.depth>1?visu.depth:0), XYZ[3]; print(title); const unsigned int dmin = cimg::min(w,h), minsiz = min_size>=0?min_size:(-min_size)*dmin/100; if (dmin=0?max_size:(-max_size)*dmax/100; if (dmax>maxsiz) { w=w*maxsiz/dmax; w+=(w==0); h=h*maxsiz/dmax; h+=(h==0); } disp = new CImgDisplay(w,h,title,3,3); XYZ[0] = visu.width/2; XYZ[1] = visu.height/2; XYZ[2] = visu.depth/2; while (!disp->is_closed && !disp->key) visu.feature_selection(0,1,*disp,XYZ); delete disp; return *this; } //! Display the current CImgList instance in a new display window. /** This function opens a new window and displays the list images of the current CImgList instance into it. Images of the list are concatenated in a single temporarly image for visualization purposes. The function returns when a key is pressed or the display window is closed by the user. \param axe : specify the axe for image concatenation. Can be 'x','y','z' or 'v'. \param align : specify the alignment for image concatenation. Can be 'p' (top), 'c' (center) or 'n' (bottom). \param min_size : specify the minimum size of the opening display window. Images having dimensions below this size will be upscaled. \param max_size : specify the maximum size of the opening display window. Images having dimensions above this size will be downscaled. \return A reference to the current CImgList instance is returned. **/ const CImgList& display(const char axe='x', const char align='c', const int min_size=128, const int max_size=1024) const { char title[256]={0}; std::sprintf(title,"CImgList<%s>",pixel_type()); return display(title,axe,align,min_size,max_size); } //! Rescale and center 3D object CImgList& resize_object3d(const float siz=100, const bool centering=true) { float xm = (float)((*this)(0,0)), ym = (float)((*this)(0,1)), zm = (float)((*this)(0,2)), xM = xm, yM = ym, zM = zm; for (unsigned int p=1; pxM) xM = x; if (y>yM) yM = y; if (z>zM) zM = z; } const float cx = 0.5f*(xm+xM), cy = 0.5f*(ym+yM), cz = 0.5f*(zm+zM), delta = cimg::max(xM-xm,yM-ym,zM-zm), ratio = (siz>=0)?siz/delta:-siz/100; if (centering) cimglist_for(*this,l) { T &x = (*this)(l,0), &y = (*this)(l,1), &z = (*this)(l,2); x = (T)((x-cx)*ratio); y = (T)((y-cy)*ratio); z = (T)((z-cz)*ratio); } else cimglist_for(*this,l) { T &x = (*this)(l,0), &y = (*this)(l,1), &z = (*this)(l,2); x = (T)(cx+(x-cx)*ratio); y = (T)(cy+(y-cy)*ratio); z = (T)(cz+(z-cz)*ratio); } return *this; } //! Get a rescaled and centered version of the 3D object CImgList get_resize_object3d(const float siz=100, const bool centering=true) const { return CImgList(*this).resize_object3d(siz,centering); } // Swap fields of two CImgList instances. CImgList& swap(CImgList& list) { cimg::swap(size,list.size); cimg::swap(allocsize,list.allocsize); cimg::swap(data,list.data); return list; } }; /* #----------------------------------------- # # # # Complete previously defined functions # # # #------------------------------------------ */ namespace cimg { //! Display a dialog box, where a user can click standard buttons. /** Up to 6 buttons can be defined in the dialog window. This function returns when a user clicked one of the button or closed the dialog window. \param title = Title of the dialog window. \param msg = Main message displayed inside the dialog window. \param button1_txt = Label of the 1st button. \param button2_txt = Label of the 2nd button. \param button3_txt = Label of the 3rd button. \param button4_txt = Label of the 4th button. \param button5_txt = Label of the 5th button. \param button6_txt = Label of the 6th button. \param logo = Logo image displayed at the left of the main message. This parameter is optional. \param centering = Tell to center the dialog window on the screen. \return The button number (from 0 to 5), or -1 if the dialog window has been closed by the user. \note If a button text is set to 0, then the corresponding button (and the followings) won't appear in the dialog box. At least one button is necessary. **/ template inline int dialog(const char *title,const char *msg, const char *button1_txt,const char *button2_txt, const char *button3_txt,const char *button4_txt, const char *button5_txt,const char *button6_txt, const CImg& logo, const bool centering = false) { #if cimg_display_type!=0 const unsigned char black[3]={0,0,0}, white[3]={255,255,255}, gray[3]={200,200,200}, gray2[3]={150,150,150}; // Create buttons and canvas graphics CImgList buttons, cbuttons, sbuttons; if (button1_txt) { buttons.insert(CImg().draw_text(button1_txt,0,0,black,gray,13)); if (button2_txt) { buttons.insert(CImg().draw_text(button2_txt,0,0,black,gray,13)); if (button3_txt) { buttons.insert(CImg().draw_text(button3_txt,0,0,black,gray,13)); if (button4_txt) { buttons.insert(CImg().draw_text(button4_txt,0,0,black,gray,13)); if (button5_txt) { buttons.insert(CImg().draw_text(button5_txt,0,0,black,gray,13)); if (button6_txt) { buttons.insert(CImg().draw_text(button6_txt,0,0,black,gray,13)); }}}}}} if (!buttons.size) throw CImgArgumentException("cimg::dialog() : No buttons have been defined. At least one is necessary"); unsigned int bw=0, bh=0; cimglist_for(buttons,l) { bw = cimg::max(bw,buttons[l].width); bh = cimg::max(bh,buttons[l].height); } bw+=8; bh+=8; if (bw<64) bw=64; if (bw>128) bw=128; if (bh<24) bh=24; if (bh>48) bh=48; CImg button = CImg(bw,bh,1,3). draw_rectangle(0,0,bw-1,bh-1,gray). draw_line(0,0,bw-1,0,white).draw_line(0,bh-1,0,0,white). draw_line(bw-1,0,bw-1,bh-1,black).draw_line(bw-1,bh-1,0,bh-1,black). draw_line(1,bh-2,bw-2,bh-2,gray2).draw_line(bw-2,bh-2,bw-2,1,gray2); CImg sbutton = CImg(bw,bh,1,3). draw_rectangle(0,0,bw-1,bh-1,gray). draw_line(0,0,bw-1,0,black).draw_line(bw-1,0,bw-1,bh-1,black). draw_line(bw-1,bh-1,0,bh-1,black).draw_line(0,bh-1,0,0,black). draw_line(1,1,bw-2,1,white).draw_line(1,bh-2,1,1,white). draw_line(bw-2,1,bw-2,bh-2,black).draw_line(bw-2,bh-2,1,bh-2,black). draw_line(2,bh-3,bw-3,bh-3,gray2).draw_line(bw-3,bh-3,bw-3,2,gray2). draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA). draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA); CImg cbutton = CImg(bw,bh,1,3). 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). draw_line(4,4,bw-5,4,black,0xAAAAAAAA).draw_line(bw-5,4,bw-5,bh-5,black,0xAAAAAAAA). draw_line(bw-5,bh-5,4,bh-5,black,0xAAAAAAAA).draw_line(4,bh-5,4,4,black,0xAAAAAAAA); cimglist_for(buttons,ll) { cbuttons.insert(CImg(cbutton).draw_image(buttons[ll],1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2)); sbuttons.insert(CImg(sbutton).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2)); buttons[ll] = CImg(button).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2); } CImg canvas; if (msg) canvas = CImg().draw_text(msg,0,0,black,gray,13); const unsigned int bwall = (buttons.size-1)*(12+bw) + bw, w = cimg::max(196U,36+logo.width+canvas.width, 24+bwall), h = cimg::max(96U,36+canvas.height+bh,36+logo.height+bh), lx = 12 + (canvas.data?0:((w-24-logo.width)/2)), ly = (h-12-bh-logo.height)/2, tx = lx+logo.width+12, ty = (h-12-bh-canvas.height)/2, bx = (w-bwall)/2, by = h-12-bh; if (canvas.data) canvas = CImg(w,h,1,3). draw_rectangle(0,0,w-1,h-1,gray). draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black). draw_image(canvas,tx,ty); else canvas = CImg(w,h,1,3). draw_rectangle(0,0,w-1,h-1,gray). draw_line(0,0,w-1,0,white).draw_line(0,h-1,0,0,white). draw_line(w-1,0,w-1,h-1,black).draw_line(w-1,h-1,0,h-1,black); if (logo.data) canvas.draw_image(logo,lx,ly); unsigned int xbuttons[6]; cimglist_for(buttons,lll) { xbuttons[lll] = bx+(bw+12)*lll; canvas.draw_image(buttons[lll],xbuttons[lll],by); } // Open window and enter events loop CImgDisplay disp(canvas,title?title:" ",0,3,false,centering?true:false); if (centering) disp.move((CImgDisplay::screen_dimx()-disp.dimx())/2, (CImgDisplay::screen_dimy()-disp.dimy())/2); bool stopflag = false, refresh = false; int oselected = -1, oclicked = -1, selected = -1, clicked = -1; while (!disp.is_closed && !stopflag) { if (refresh) { if (clicked>=0) CImg(canvas).draw_image(cbuttons[clicked],xbuttons[clicked],by).display(disp); else { if (selected>=0) CImg(canvas).draw_image(sbuttons[selected],xbuttons[selected],by).display(disp); else canvas.display(disp); } refresh = false; } disp.wait(15); if (disp.is_resized) disp.resize(disp); if (disp.button&1) { oclicked = clicked; clicked = -1; cimglist_for(buttons,l) if (disp.mouse_y>=(int)by && disp.mouse_y<(int)(by+bh) && disp.mouse_x>=(int)xbuttons[l] && disp.mouse_x<(int)(xbuttons[l]+bw)) { clicked = selected = l; refresh = true; } if (clicked!=oclicked) refresh = true; } else if (clicked>=0) stopflag = true; if (disp.key) { oselected = selected; switch (disp.key) { case cimg::keyESC: selected=-1; stopflag=true; break; case cimg::keyENTER: if (selected<0) selected=0; stopflag = true; break; case cimg::keyTAB: case cimg::keyARROWRIGHT: case cimg::keyARROWDOWN: selected = (selected+1)%buttons.size; break; case cimg::keyARROWLEFT: case cimg::keyARROWUP: selected = (selected+buttons.size-1)%buttons.size; break; } disp.key = 0; if (selected!=oselected) refresh = true; } } if (!disp) selected = -1; return selected; #else std::fprintf(stderr,"<%s>\n\n%s\n\n",title,msg); return -1+0*(int)(button1_txt-button2_txt+button3_txt-button4_txt+button5_txt-button6_txt+logo.width+(int)centering); #endif } inline int dialog(const char *title,const char *msg, const char *button1_txt,const char *button2_txt,const char *button3_txt, const char *button4_txt,const char *button5_txt,const char *button6_txt, const bool centering) { return dialog(title,msg,button1_txt,button2_txt,button3_txt,button4_txt,button5_txt,button6_txt, CImg::get_logo40x38(),centering); } // Inner routine used by the Marching cube algorithm template inline int _marching_cubes_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) { switch (edge) { case 0: return indices1(x,y,0); case 1: return indices1(nx,y,1); case 2: return indices1(x,ny,0); case 3: return indices1(x,y,1); case 4: return indices2(x,y,0); case 5: return indices2(nx,y,1); case 6: return indices2(x,ny,0); case 7: return indices2(x,y,1); case 8: return indices1(x,y,2); case 9: return indices1(nx,y,2); case 10: return indices1(nx,ny,2); case 11: return indices1(x,ny,2); } return 0; } //! Polygonize an implicit function // This function uses the Marching Cubes Tables published on the web page : // http://astronomy.swin.edu.au/~pbourke/modelling/polygonise/ template inline void marching_cubes(const tfunc& func, const float isovalue, const float x0,const float y0,const float z0, const float x1,const float y1,const float z1, const float resx,const float resy,const float resz, CImgList& points, CImgList& primitives, const bool invert_faces) { static unsigned int edges[256]={ 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 }; static int triangles[256][16] = {{-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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}, {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}}; const unsigned int nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1, ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1, nz = (unsigned int)((z1-z0+1)/resz), nzm1 = nz-1; if (!nxm1 || !nym1 || !nzm1) return; CImg indices1(nx,ny,1,3,-1), indices2(indices1); CImg values1(nx,ny), values2(nx,ny); float X=0, Y=0, Z=0, nX=0, nY=0, nZ=0; // Fill the first plane with function values Y=y0; cimg_forY(values1,y) { X = x0; cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=resx; } Y+=resy; } // Run Marching Cubes algorithm Z = z0; nZ = Z + resz; for (unsigned int zi=0; zi::vector(Xi,Y,Z)); } if ((edge&2) && indices1(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val1)*resy/(val2-val1); indices1(nxi,yi,1) = points.size; points.insert(CImg::vector(nX,Yi,Z)); } if ((edge&4) && indices1(xi,nyi,0)<0) { const float Xi = X + (isovalue-val3)*resx/(val2-val3); indices1(xi,nyi,0) = points.size; points.insert(CImg::vector(Xi,nY,Z)); } if ((edge&8) && indices1(xi,yi,1)<0) { const float Yi = Y + (isovalue-val0)*resy/(val3-val0); indices1(xi,yi,1) = points.size; points.insert(CImg::vector(X,Yi,Z)); } if ((edge&16) && indices2(xi,yi,0)<0) { const float Xi = X + (isovalue-val4)*resx/(val5-val4); indices2(xi,yi,0) = points.size; points.insert(CImg::vector(Xi,Y,nZ)); } if ((edge&32) && indices2(nxi,yi,1)<0) { const float Yi = Y + (isovalue-val5)*resy/(val6-val5); indices2(nxi,yi,1) = points.size; points.insert(CImg::vector(nX,Yi,nZ)); } if ((edge&64) && indices2(xi,nyi,0)<0) { const float Xi = X + (isovalue-val7)*resx/(val6-val7); indices2(xi,nyi,0) = points.size; points.insert(CImg::vector(Xi,nY,nZ)); } if ((edge&128) && indices2(xi,yi,1)<0) { const float Yi = Y + (isovalue-val4)*resy/(val7-val4); indices2(xi,yi,1) = points.size; points.insert(CImg::vector(X,Yi,nZ)); } if ((edge&256) && indices1(xi,yi,2)<0) { const float Zi = Z+ (isovalue-val0)*resz/(val4-val0); indices1(xi,yi,2) = points.size; points.insert(CImg::vector(X,Y,Zi)); } if ((edge&512) && indices1(nxi,yi,2)<0) { const float Zi = Z + (isovalue-val1)*resz/(val5-val1); indices1(nxi,yi,2) = points.size; points.insert(CImg::vector(nX,Y,Zi)); } if ((edge&1024) && indices1(nxi,nyi,2)<0) { const float Zi = Z + (isovalue-val2)*resz/(val6-val2); indices1(nxi,nyi,2) = points.size; points.insert(CImg::vector(nX,nY,Zi)); } if ((edge&2048) && indices1(xi,nyi,2)<0) { const float Zi = Z + (isovalue-val3)*resz/(val7-val3); indices1(xi,nyi,2) = points.size; points.insert(CImg::vector(X,nY,Zi)); } // Create triangles for (int *triangle=triangles[configuration]; *triangle!=-1; ) { const unsigned int p0 = *(triangle++), p1 = *(triangle++), p2 = *(triangle++); const tf i0 = (tf)(_marching_cubes_indice(p0,indices1,indices2,xi,yi,nxi,nyi)), i1 = (tf)(_marching_cubes_indice(p1,indices1,indices2,xi,yi,nxi,nyi)), i2 = (tf)(_marching_cubes_indice(p2,indices1,indices2,xi,yi,nxi,nyi)); if (invert_faces) primitives.insert(CImg::vector(i0,i1,i2)); else primitives.insert(CImg::vector(i0,i2,i1)); } } } } cimg::swap(values1,values2); cimg::swap(indices1,indices2); } } // Inner routine used by the Marching square algorithm template inline int _marching_squares_indice(const unsigned int edge, const CImg& indices1, const CImg& indices2, const unsigned int x, const unsigned int nx) { switch (edge) { case 0: return (int)indices1(x,0); case 1: return (int)indices1(nx,1); case 2: return (int)indices2(x,0); case 3: return (int)indices1(x,1); } return 0; } //! Polygonize an implicit 2D function by the marching squares algorithm template inline void marching_squares(const tfunc& func, const float isovalue, const float x0,const float y0, const float x1,const float y1, const float resx,const float resy, CImgList& points, CImgList& primitives) { static unsigned int edges[16]={ 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 }; static int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 }, { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 }, { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 }, { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } }; const unsigned int nx = (unsigned int)((x1-x0+1)/resx), nxm1 = nx-1, ny = (unsigned int)((y1-y0+1)/resy), nym1 = ny-1; if (!nxm1 || !nym1) return; CImg indices1(nx,1,1,2,-1), indices2(nx,1,1,2); CImg values1(nx), values2(nx); float X = 0, Y = 0, nX = 0, nY = 0; // Fill first line with values cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=resx; } // Run the marching squares algorithm Y = y0; nY = Y + resy; for (unsigned int yi=0, nyi=1; yi::vector(Xi,Y)); } if ((edge&2) && indices1(nxi,1)<0) { const float Yi = Y + (isovalue-val1)*resy/(val2-val1); indices1(nxi,1) = points.size; points.insert(CImg::vector(nX,Yi)); } if ((edge&4) && indices2(xi,0)<0) { const float Xi = X + (isovalue-val3)*resx/(val2-val3); indices2(xi,0) = points.size; points.insert(CImg::vector(Xi,nY)); } if ((edge&8) && indices1(xi,1)<0) { const float Yi = Y + (isovalue-val0)*resy/(val3-val0); indices1(xi,1) = points.size; points.insert(CImg::vector(X,Yi)); } // Create segments for (int *segment=segments[configuration]; *segment!=-1; ) { const unsigned int p0 = *(segment++), p1 = *(segment++); const tf i0 = (tf)(_marching_squares_indice(p0,indices1,indices2,xi,nxi)), i1 = (tf)(_marching_squares_indice(p1,indices1,indices2,xi,nxi)); primitives.insert(CImg::vector(i0,i1)); } } } values1.swap(values2); indices1.swap(indices2); } } // End of cimg:: namespace } // End of cimg_library:: namespace } #ifdef cimg_use_visualcpp6 #undef std #endif #ifdef cimg_redefine_min #define min(a,b) (((a)<(b))?(a):(b)) #endif #ifdef cimg_redefine_max #define max(a,b) (((a)>(b))?(b):(a)) #endif #endif // Local Variables: // mode: c++ // End: