| /* |
| # |
| # 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.20 |
| |
| // Detect Microsoft VC++ 6.0 compiler to get some workarounds afterwards. |
| #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 <cstdio> |
| #include <cstdlib> |
| #include <cstdarg> |
| #include <cstring> |
| #include <cmath> |
| #include <ctime> |
| |
| // Overcome VisualC++ 6.0 compilers namespace 'std::' bug. |
| #ifdef cimg_use_visualcpp6 |
| #define std |
| #endif |
| |
| /* |
| # |
| # 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 |
| #if defined(sun) || defined(__sun) || defined(linux) || defined(__linux) \ |
| || defined(__linux__) || defined(__CYGWIN__) || defined(BSD) || defined(__FreeBSD__) \ |
| || defined(__OPENBSD__) || defined(__MACOSX__) || defined(__APPLE__) || defined(sgi) \ |
| || defined(__sgi) |
| // Unix-like (Linux, Solaris, BSD, MacOSX, Irix,...). |
| #define cimg_OS 1 |
| #ifndef cimg_display_type |
| #define cimg_display_type 1 |
| #endif |
| #ifndef cimg_color_terminal |
| #define cimg_color_terminal |
| #endif |
| #elif defined(_WIN32) || defined(__WIN32__) |
| // Windows. |
| #define cimg_OS 2 |
| #ifndef cimg_display_type |
| #define cimg_display_type 2 |
| #endif |
| #else |
| // Unknown configuration : ask for minimal dependencies (no display). |
| #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 |
| |
| // Allow compatibility with older CImg versions. |
| // |
| // Define 'cimg_strict' to avoid keeping the compatibility with older code |
| #ifndef cimg_strict |
| #define CImgl CImgList |
| #define cimgl_map cimglist_for |
| #define cimglist_map cimglist_for |
| #define cimg_map cimg_for |
| #define cimg_mapoff cimg_foroff |
| #define cimg_mapX cimg_forX |
| #define cimg_mapY cimg_forY |
| #define cimg_mapZ cimg_forZ |
| #define cimg_mapV cimg_forV |
| #define cimg_mapXY cimg_forXY |
| #define cimg_mapXZ cimg_forXZ |
| #define cimg_mapXV cimg_forXV |
| #define cimg_mapYZ cimg_forYZ |
| #define cimg_mapYV cimg_forYV |
| #define cimg_mapZV cimg_forZV |
| #define cimg_mapXYZ cimg_forXYZ |
| #define cimg_mapXYV cimg_forXYV |
| #define cimg_mapXZV cimg_forXZV |
| #define cimg_mapYZV cimg_forYZV |
| #define cimg_mapXYZV cimg_forXYZV |
| #define cimg_imapX cimg_for_insideX |
| #define cimg_imapY cimg_for_insideY |
| #define cimg_imapZ cimg_for_insideZ |
| #define cimg_imapV cimg_for_insideV |
| #define cimg_imapXY cimg_for_insideXY |
| #define cimg_imapXYZ cimg_for_insideXYZ |
| #define cimg_bmapX cimg_for_borderX |
| #define cimg_bmapY cimg_for_borderY |
| #define cimg_bmapZ cimg_for_borderZ |
| #define cimg_bmapV cimg_for_borderV |
| #define cimg_bmapXY cimg_for_borderXY |
| #define cimg_bmapXYZ cimg_for_borderXYZ |
| #define cimg_2mapX cimg_for2X |
| #define cimg_2mapY cimg_for2Y |
| #define cimg_2mapZ cimg_for2Z |
| #define cimg_2mapXY cimg_for2XY |
| #define cimg_2mapXZ cimg_for2XZ |
| #define cimg_2mapYZ cimg_for2YZ |
| #define cimg_2mapXYZ cimg_for2XYZ |
| #define cimg_3mapX cimg_for3X |
| #define cimg_3mapY cimg_for3Y |
| #define cimg_3mapZ cimg_for3Z |
| #define cimg_3mapXY cimg_for3XY |
| #define cimg_3mapXZ cimg_for3XZ |
| #define cimg_3mapYZ cimg_for3YZ |
| #define cimg_3mapXYZ cimg_for3XYZ |
| #define cimg_4mapX cimg_for4X |
| #define cimg_4mapY cimg_for4Y |
| #define cimg_4mapZ cimg_for4Z |
| #define cimg_4mapXY cimg_for4XY |
| #define cimg_4mapXZ cimg_for4XZ |
| #define cimg_4mapYZ cimg_for4YZ |
| #define cimg_4mapXYZ cimg_for4XYZ |
| #define cimg_5mapX cimg_for5X |
| #define cimg_5mapY cimg_for5Y |
| #define cimg_5mapZ cimg_for5Z |
| #define cimg_5mapXY cimg_for5XY |
| #define cimg_5mapXZ cimg_for5XZ |
| #define cimg_5mapYZ cimg_for5YZ |
| #define cimg_5mapXYZ cimg_for5XYZ |
| #define cimg_map2x2x1 cimg_for2x2 |
| #define cimg_map3x3x1 cimg_for3x3 |
| #define cimg_map4x4x1 cimg_for4x4 |
| #define cimg_map5x5x1 cimg_for5x5 |
| #define cimg_map2x2 cimg_for2x2 |
| #define cimg_map3x3 cimg_for3x3 |
| #define cimg_map4x4 cimg_for4x4 |
| #define cimg_map5x5 cimg_for5x5 |
| #define cimg_map3x3x3 cimg_for3x3x3 |
| #define cimg_map2x2x2 cimg_for2x2x2 |
| #define CImg_2x2x1 CImg_2x2 |
| #define CImg_3x3x1 CImg_3x3 |
| #define CImg_4x4x1 CImg_4x4 |
| #define CImg_5x5x1 CImg_5x5 |
| #define scroll translate |
| #define cimg_convert_path cimg_imagemagick_path |
| #define load_convert load_imagemagick |
| #define save_convert save_imagemagick |
| #endif |
| |
| // Architecture-dependent includes. |
| #if cimg_OS==1 |
| #include <sys/time.h> |
| #include <unistd.h> |
| #elif cimg_OS==2 |
| #include <windows.h> |
| // Discard unuseful macros in windows.h |
| // to allow compilation with VC++ 6.0. |
| #ifdef min |
| #undef min |
| #undef max |
| #undef abs |
| #endif |
| #endif |
| // Display-dependent includes. |
| #if cimg_display_type==1 |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| #include <X11/keysym.h> |
| #include <pthread.h> |
| #ifdef cimg_use_xshm |
| #include <sys/ipc.h> |
| #include <sys/shm.h> |
| #include <X11/extensions/XShm.h> |
| #endif |
| #ifdef cimg_use_xrandr |
| #include <X11/extensions/Xrandr.h> |
| #endif |
| #endif |
| |
| // Configuration for native PNG and JPEG support |
| // |
| // 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##ap=(tab)[7], \ |
| &I##pn=(tab)[8],&I##cn=(tab)[9],&I##nn=(tab)[10],&I##aa=(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_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<typename T=float> struct CImg; |
| template<typename T=float> 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<typename tfunc, typename tp, typename tf> |
| 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<tp>& points, CImgList<tf>& primitives, |
| const bool invert_faces = false); |
| |
| template<typename tfunc, typename tp, typename tf> |
| 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<tp>& points, CImgList<tf>& primitives); |
| } |
| |
| /* |
| #---------------------------------------------- |
| # |
| # |
| # Definition of the CImgException structures |
| # |
| # |
| #---------------------------------------------- |
| */ |
| |
| // Never use the following macro in your own code ! |
| #define cimg_exception_err(etype,disp_flag) \ |
| if (cimg::exception_mode()>=1) { \ |
| std::va_list ap; \ |
| va_start(ap,format); \ |
| std::vsprintf(message,format,ap); \ |
| va_end(ap); \ |
| 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<float> 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<float> 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<float> 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 <tt>try { ... } catch() { ... }</tt>. |
| In this case, you can avoid the apparition of the modal window, by |
| defining the environment variable <tt>cimg_debug</tt> 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 <tt>using namespace cimg_library::cimg;</tt> in your source code, since a lot of functions of the |
| <tt>cimg::</tt> namespace have prototypes similar to standard C functions defined in the global namespace <tt>::</tt>. |
| **/ |
| 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<typename T,typename t> struct largest { typedef t type; }; |
| template<> struct largest<unsigned char,bool> { typedef unsigned char type; }; |
| template<> struct largest<unsigned char,char> { typedef short type; }; |
| template<> struct largest<char,bool> { typedef char type; }; |
| template<> struct largest<char,unsigned char> { typedef short type; }; |
| template<> struct largest<char,unsigned short> { typedef int type; }; |
| template<> struct largest<char,unsigned int> { typedef unsigned int type; }; |
| template<> struct largest<char,unsigned long> { typedef unsigned long type; }; |
| template<> struct largest<unsigned short,bool> { typedef unsigned short type; }; |
| template<> struct largest<unsigned short,unsigned char> { typedef unsigned short type; }; |
| template<> struct largest<unsigned short,char> { typedef int type; }; |
| template<> struct largest<unsigned short,short> { typedef int type; }; |
| template<> struct largest<short,bool> { typedef short type; }; |
| template<> struct largest<short,unsigned char> { typedef short type; }; |
| template<> struct largest<short,char> { typedef short type; }; |
| template<> struct largest<short,unsigned short> { typedef int type; }; |
| template<> struct largest<short,unsigned int> { typedef unsigned int type; }; |
| template<> struct largest<short,unsigned long> { typedef unsigned long type; }; |
| template<> struct largest<unsigned int,bool> { typedef unsigned int type; }; |
| template<> struct largest<unsigned int,unsigned char> { typedef unsigned int type; }; |
| template<> struct largest<unsigned int,char> { typedef unsigned int type; }; |
| template<> struct largest<unsigned int,unsigned short> { typedef unsigned int type; }; |
| template<> struct largest<unsigned int,short> { typedef unsigned int type; }; |
| template<> struct largest<unsigned int,int> { typedef unsigned int type; }; |
| template<> struct largest<int,bool> { typedef int type; }; |
| template<> struct largest<int,unsigned char> { typedef int type; }; |
| template<> struct largest<int,char> { typedef int type; }; |
| template<> struct largest<int,unsigned short> { typedef int type; }; |
| template<> struct largest<int,short> { typedef int type; }; |
| template<> struct largest<int,unsigned int> { typedef unsigned int type; }; |
| template<> struct largest<int,unsigned long> { typedef unsigned long type; }; |
| template<> struct largest<float,bool> { typedef float type; }; |
| template<> struct largest<float,unsigned char> { typedef float type; }; |
| template<> struct largest<float,char> { typedef float type; }; |
| template<> struct largest<float,unsigned short> { typedef float type; }; |
| template<> struct largest<float,short> { typedef float type; }; |
| template<> struct largest<float,unsigned int> { typedef float type; }; |
| template<> struct largest<float,int> { typedef float type; }; |
| template<> struct largest<float,unsigned long> { typedef float type; }; |
| template<> struct largest<float,long> { typedef float type; }; |
| template<> struct largest<double,bool> { typedef double type; }; |
| template<> struct largest<double,unsigned char> { typedef double type; }; |
| template<> struct largest<double,char> { typedef double type; }; |
| template<> struct largest<double,unsigned short> { typedef double type; }; |
| template<> struct largest<double,short> { typedef double type; }; |
| template<> struct largest<double,unsigned int> { typedef double type; }; |
| template<> struct largest<double,int> { typedef double type; }; |
| template<> struct largest<double,unsigned long> { typedef double type; }; |
| template<> struct largest<double,long> { typedef double type; }; |
| template<> struct largest<double,float> { typedef double type; }; |
| |
| template<typename T> 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<bool> { |
| 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<unsigned char> { |
| 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<char> { |
| static char min() { return (char)-1<<(8*sizeof(char)-1); } |
| static char max() { return ~((char)-1<<(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<unsigned short> { |
| 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<short> { |
| static short min() { return (short)-1<<(8*sizeof(short)-1); } |
| static short max() { return ~((short)-1<<(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<unsigned int> { |
| 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<int> { |
| static int min() { return (int)-1<<(8*sizeof(int)-1); } |
| static int max() { return ~((int)-1<<(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<unsigned long> { |
| 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<long> { |
| static long min() { return (long)-1<<(8*sizeof(long)-1); } |
| static long max() { return ~((long)-1<<(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<float> { |
| 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<double> { |
| 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 |
| |
| #ifdef PI |
| #undef PI |
| #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<CImg Warning> "); |
| 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<l; k++) n+=std::abs(s1[k] - s2[k]); return n; } |
| return 0; |
| } |
| |
| inline int strncasecmp(const char *s1,const char *s2,const int l) { |
| if (s1 && s2) { int n=0; for (int k=0; k<l; k++) n+=std::abs(uncase(s1[k])-uncase(s2[k])); return n; } |
| return 0; |
| } |
| |
| inline int strcmp(const char *s1,const char *s2) { |
| const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2); |
| return cimg::strncmp(s1,s2,1+(l1<l2?l1:l2)); |
| } |
| |
| inline int strcasecmp(const char *s1,const char *s2) { |
| const int l1 = cimg::strlen(s1), l2 = cimg::strlen(s2); |
| return cimg::strncasecmp(s1,s2,1+(l1<l2?l1:l2)); |
| } |
| |
| inline int strfind(const char *s,const char c) { |
| if (s) { |
| int l; for (l=cimg::strlen(s); l>=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; |
| } |
| |
| //! Return path of the ImageMagick's \c convert tool. |
| /** |
| If you have installed the <a href="http://www.imagemagick.org">ImageMagick package</a> |
| 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 <tt>CImg.h</tt> 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 |
| 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,"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,"C:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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; } |
| }} |
| { for (unsigned int k=0; k<=9 && !path_found; k++) { |
| std::sprintf(st_imagemagick_path,"D:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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 |
| } |
| return st_imagemagick_path; |
| } |
| |
| //! Return path of the GraphicsMagick's \c gm tool. |
| /** |
| If you have installed the <a href="http://www.graphicsmagick.org">GraphicsMagick package</a> |
| 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 <tt>CImg.h</tt> 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 |
| 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,"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,"C:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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; } |
| }} |
| { for (unsigned int k=0; k<=9 && !path_found; k++) { |
| std::sprintf(st_graphicsmagick_path,"D:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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:\\PROGRA~1\\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 |
| } |
| return st_graphicsmagick_path; |
| } |
| |
| //! Return path of the \c XMedcon tool. |
| /** |
| If you have installed the <a href="http://xmedcon.sourceforge.net/">XMedcon package</a> |
| 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 <tt>CImg.h</tt> 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 |
| 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,"C:\\PROGRA~1\\XMedCon\\bin\\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,"D:\\PROGRA~1\\XMedCon\\bin\\medcon.bat"); |
| 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 |
| } |
| 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 <tt>CImg.h</tt> |
| 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 |
| #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<typename T> 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))<wlimitT?toread:wlimit; |
| lalread = (unsigned int)std::fread((void*)(ptr+alread),sizeof(T),ltoread,stream); |
| alread+=lalread; |
| toread-=lalread; |
| } while (ltoread==lalread && toread>0); |
| cimg::warn(toread>0,"cimg::fread() : File reading problems, only %u/%u elements read",alread,nmemb); |
| return alread; |
| } |
| |
| template<typename T> 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))<wlimitT?towrite:wlimit; |
| lalwrite = (unsigned int)std::fwrite((void*)(ptr+alwrite),sizeof(T),ltowrite,stream); |
| alwrite+=lalwrite; |
| towrite-=lalwrite; |
| } while (ltowrite==lalwrite && towrite>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<typename T> inline void swap(T& a,T& b) { T t=a; a=b; b=t; } |
| template<typename T1,typename T2> inline void swap(T1& a1,T1& b1,T2& a2,T2& b2) { |
| cimg::swap(a1,b1); cimg::swap(a2,b2); |
| } |
| template<typename T1,typename T2,typename T3> 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<typename T1,typename T2,typename T3,typename T4> |
| 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<typename T1,typename T2,typename T3,typename T4,typename T5> |
| 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<typename T1,typename T2,typename T3,typename T4,typename T5,typename T6> |
| 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<typename T> 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<typename T> 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<argc && cimg::strcmp(argv[k],name)) k++; |
| i=k; |
| res=(k++==argc?defaut:(k==argc?argv[--k]:argv[k])); |
| } else res = defaut; |
| if (visu && usage) std::fprintf(stderr," %s%-8s%s = %-12s : %s%s%s\n", |
| cimg::t_bold,name,cimg::t_normal,res?res:"0",cimg::t_purple,usage,cimg::t_normal); |
| } |
| return res; |
| } |
| |
| inline bool option(const char *const name, const int argc, char **argv, |
| const bool defaut, const char *const usage=0) { |
| const char *s = cimg::option(name,argc,argv,(char*)0); |
| const bool res = s?(cimg::strcasecmp(s,"false") && cimg::strcasecmp(s,"off") && cimg::strcasecmp(s,"0")):defaut; |
| cimg::option(name,0,0,res?"true":"false",usage); |
| return res; |
| } |
| |
| inline int option(const char *const name, const int argc, char **argv, |
| const int defaut, const char *const usage=0) { |
| const char *s = cimg::option(name,argc,argv,(char*)0); |
| const int res = s?std::atoi(s):defaut; |
| char tmp[256]; |
| std::sprintf(tmp,"%d",res); |
| cimg::option(name,0,0,tmp,usage); |
| return res; |
| } |
| |
| inline char option(const char *const name, const int argc, char **argv, |
| const char defaut, const char *const usage=0) { |
| const char *s = cimg::option(name,argc,argv,(char*)0); |
| const char res = s?s[0]:defaut; |
| char tmp[8]; |
| tmp[0] = res; |
| tmp[1] ='\0'; |
| cimg::option(name,0,0,tmp,usage); |
| return res; |
| } |
| |
| inline float option(const char *const name, const int argc, char **argv, |
| const float defaut, const char *const usage=0) { |
| const char *s = cimg::option(name,argc,argv,(char*)0); |
| const float res = s?cimg::atof(s):defaut; |
| char tmp[256]; |
| std::sprintf(tmp,"%g",res); |
| cimg::option(name,0,0,tmp,usage); |
| return res; |
| } |
| |
| inline double option(const char *const name, const int argc, char **argv, |
| const double defaut, const char *const usage=0) { |
| const char *s = cimg::option(name,argc,argv,(char*)0); |
| const double res = s?cimg::atof(s):defaut; |
| char tmp[256]; |
| std::sprintf(tmp,"%g",res); |
| cimg::option(name,0,0,tmp,usage); |
| return res; |
| } |
| |
| //! Return \c false for little endian CPUs (Intel), \c true for big endian CPUs (Motorola). |
| inline bool endian() { |
| const int x=1; |
| return ((unsigned char*)&x)[0]?false:true; |
| } |
| |
| //! Print informations about %CImg environement variables. |
| /** |
| Printing is done on the standart error output. |
| **/ |
| inline void info() { |
| char tmp[1024] = {0}; |
| std::fprintf(stderr,"\n %sCImg Library %g%s, compiled %s ( %s ) with the following flags :\n\n", |
| cimg::t_red,cimg_version,cimg::t_normal,__DATE__,__TIME__); |
| |
| std::fprintf(stderr," > 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_visual_cpp6' 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<typename T> inline const T rol(const T& a, const unsigned int n=1) { |
| return (T)((a<<n)|(a>>((sizeof(T)<<3)-n))); |
| } |
| |
| template<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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<typename T> 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. |
| **/ |
| inline double mod(const double x, const double m) { return x-m*std::floor(x/m); } |
| inline float mod(const float x, const float m) { return (float)(x-m*std::floor((double)x/m)); } |
| inline int mod(const int x, const int m) { return x>=0?x%m:(x%m?m+x%m:0); } |
| |
| //! 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<typename T> inline T minmod(const T& a,const T& b) { return a*b<=0?0:(a>0?(a<b?a:b):(a<b?b:a)); } |
| |
| //! Return a random variable between [0,1], followin a uniform distribution. |
| inline double rand() { return (double)std::rand()/RAND_MAX; } |
| |
| //! Return a random variable between [-1,1], following a uniform distribution. |
| inline double crand() { return 1-2*cimg::rand(); } |
| |
| //! Return a random variable following a gaussian distribution and a standard deviation of 1. |
| inline double grand() { |
| return std::sqrt(-2*std::log((double)(1e-10 + (1-2e-10)*cimg::rand())))*std::cos((double)(2*PI*cimg::rand())); |
| } |
| |
| inline double pythagore(double a, double b) { |
| const double absa = cimg::abs(a), absb = cimg::abs(b); |
| if (absa>absb) { 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 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<T> or a list CImgList<T> |
| 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<float> 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<typename T> CImgStats(const CImg<T>& img, const bool compute_variance=true) { |
| assign(img,compute_variance); |
| } |
| |
| //! In-place version of the previous constructor. |
| template<typename T> CImgStats& assign(const CImg<T>& img, const bool compute_variance=true) { |
| if (img.is_empty()) |
| 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 (a<pmin) { pmin=a; ptrmin = ptr; } |
| if (a>pmax) { 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<typename T> CImgStats(const CImgList<T>& list, const bool compute_variance=true) { |
| assign(list,compute_variance); |
| } |
| |
| //! In-place version of the previous constructor. |
| template<typename T> CImgStats& assign(const CImgList<T>& list,const bool compute_variance=true) { |
| if (list.is_empty()) |
| 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 (a<pmin) { pmin=a; ptrmin = ptr; lmin = l; } |
| if (a>pmax) { pmax=a; ptrmax = ptr; lmax = l; } |
| } |
| psize+=list[l].size(); |
| } |
| mean/=psize; |
| min=(double)pmin; |
| max=(double)pmax; |
| const CImg<T> &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; |
| } |
| |
| //! Assignement 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); |
| } |
| |
| //! Print the current statistics. |
| /** |
| Printing is done on the standart 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<T> image |
| of a \c CImgList<T> 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; |
| |
| //! Fullscreen state of the display |
| bool is_fullscreen; |
| |
| //! 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; |
| |
| float fps_fps, min, max; |
| unsigned long timer, fps_frames, fps_timer; |
| |
| #ifdef cimgdisplay_plugin |
| #include cimgdisplay_plugin |
| #endif |
| |
| //! 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),is_fullscreen(false),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), |
| 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<typename T> |
| CImgDisplay(const CImg<T>& 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),is_fullscreen(false),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),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<typename T> |
| CImgDisplay(const CImgList<T>& 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),is_fullscreen(false),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),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),is_fullscreen(false),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),min(0),max(0) { |
| assign(disp); |
| } |
| |
| //! Destructor |
| ~CImgDisplay() { |
| _assign(); |
| } |
| |
| //! Assignement operator |
| CImgDisplay& operator=(const CImgDisplay& disp) { |
| return assign(disp); |
| } |
| |
| //! 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() { |
| 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<T> 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<typename T> CImgDisplay& display(const CImgList<T>& list,const char axe='x',const char align='c') { |
| return display(list.get_append(axe,align)); |
| } |
| |
| //! Display an image CImg<T> into a display window. |
| template<typename T> CImgDisplay& operator<<(const CImg<T>& img) { |
| return display(img); |
| } |
| |
| //! Display an image CImg<T> into a display window. |
| template<typename T> CImgDisplay& operator<<(const CImgList<T>& 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<typename T> CImgDisplay& resize(const CImg<T>& 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<typename tp, typename tf, typename T, typename to> |
| CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_light=0.05f, |
| const bool display_axes = true, float *const pose_matrix=0) { |
| CImg<T>(width,height,1,3,0).display_object3d(points,primitives,colors,opacities,*this, |
| centering,render_static,render_motion, |
| double_sided,focale,ambiant_light,display_axes,pose_matrix); |
| return *this; |
| } |
| |
| //! Display a 3D object. |
| template<typename tp, typename tf, typename T> |
| CImgDisplay& display_object3d(const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_light=0.05f, |
| const float opacity=1.0f, const bool display_axes = true, float *const pose_matrix=0) { |
| typedef typename cimg::largest<tp,float>::type to; |
| CImg<T>(width,height,1,3,0).display_object3d(points,primitives,colors, |
| CImg<to>(primitives.size)=(to)opacity,*this, |
| centering,render_static,render_motion, |
| double_sided,focale,ambiant_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<typename t, typename T> 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<wd; x++) { old=curr; curr+=s; *(poffx++) = (unsigned int)curr-(unsigned int)old; } |
| s = (float)hs/hd; |
| poffy = offy; curr=0; for (unsigned int y=0; y<hd; y++) { old=curr; curr+=s; *(poffy++) = ws*((unsigned int)curr-(unsigned int)old); } |
| *poffy=0; |
| poffy = offy; |
| {for (unsigned int y=0; y<hd; ) { |
| const T *ptr = ptrs; |
| poffx = offx; |
| for (unsigned int x=0; x<wd; x++) { *(ptrd++)=*ptr; ptr+=*(poffx++); } |
| y++; |
| unsigned int dy=*(poffy++); |
| for (;!dy && y<hd; std::memcpy(ptrd, ptrd-wd, sizeof(t)*wd), y++, ptrd+=wd, dy=*(poffy++)); |
| ptrs+=dy; |
| }} |
| delete[] offx; delete[] offy; |
| } |
| |
| //! Test if a specific key is pressed |
| bool is_pressed(const unsigned int key1) const { |
| bool pressed = false; |
| for (unsigned int i=0; i<256; ++i) { |
| if (released_keys[i]==key1) { pressed = false; break; } |
| if (keys[i]==key1) { pressed = true; break; } |
| } |
| return pressed; |
| } |
| |
| //! Test if a key sequence has been typed |
| bool is_typed(const unsigned int *const keyseq, const unsigned int N, const bool remove=true) { |
| if (keyseq && N) { |
| const unsigned int *const ps_end = keyseq+N-1, k = *ps_end, *const pk_end = (unsigned int*)keys+257-N; |
| for (unsigned int *pk = (unsigned int*)keys; pk<pk_end; ) { |
| if (*(pk++)==k) { |
| bool res = true; |
| const unsigned int *ps = ps_end, *pk2 = pk; |
| for (unsigned int i=1; i<N; ++i) res = (*(--ps)==*(pk2++)); |
| if (res) { |
| if (remove) std::memset((void*)(pk-1),0,sizeof(unsigned int)*N); |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const bool remove=true) { |
| return is_typed(&key1,1,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const bool remove=true) { |
| const unsigned int seq[2] = { key1, key2 }; |
| return is_typed(seq,2,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, const bool remove=true) { |
| const unsigned int seq[3] = { key1, key2, key3 }; |
| return is_typed(seq,3,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const bool remove=true) { |
| const unsigned int seq[4] = { key1, key2, key3, key4 }; |
| return is_typed(seq,4,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const unsigned int key5, const bool remove=true) { |
| const unsigned int seq[5] = { key1, key2, key3, key4,key5 }; |
| return is_typed(seq,5,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const unsigned int key5, const unsigned int key6, const bool remove=true) { |
| const unsigned int seq[6] = { key1, key2, key3, key4,key5,key6 }; |
| return is_typed(seq,6,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const unsigned int key5, const unsigned int key6, |
| const unsigned int key7, const bool remove=true) { |
| const unsigned int seq[7] = { key1, key2, key3, key4,key5,key6,key7 }; |
| return is_typed(seq,7,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const unsigned int key5, const unsigned int key6, |
| const unsigned int key7, const unsigned int key8, const bool remove=true) { |
| const unsigned int seq[8] = { key1, key2, key3, key4,key5,key6,key7,key8 }; |
| return is_typed(seq,8,remove); |
| } |
| |
| //! Test if a key combination has been typed |
| bool is_typed(const unsigned int key1, const unsigned int key2, const unsigned int key3, |
| const unsigned int key4, const unsigned int key5, const unsigned int key6, |
| const unsigned int key7, const unsigned int key8, const unsigned int key9, const bool remove=true) { |
| const unsigned int seq[9] = { key1, key2, key3, key4,key5,key6,key7,key8,key9 }; |
| return is_typed(seq,9,remove); |
| } |
| |
| // When no display available |
| //--------------------------- |
| #if cimg_display_type==0 |
| |
| //! Return the width of the screen resolution. |
| static int screen_dimx() { |
| return 0; |
| } |
| |
| //! Return the height of the screen resolution. |
| static int screen_dimy() { |
| return 0; |
| } |
| |
| //! In-place version of the previous constructor |
| 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) { |
| throw CImgDisplayException("CImgDisplay() : Display has been required but is not available (cimg_display_type=0)"); |
| fps_timer = 0*(unsigned long)(dimw + dimh + title + normalization_type + events_type + (int)fullscreen_flag + (int)closed_flag); |
| return *this; |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename T> CImgDisplay& assign(const CImg<T>& 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<typename T> CImgDisplay& assign(const CImgList<T>& 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); |
| } |
| |
| // In-place version of the destructor (should not be used by the user). |
| CImgDisplay& _assign() { |
| return *this; |
| } |
| |
| //! Display an image in a window. |
| template<typename T> CImgDisplay& display(const CImg<T>& 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<typename T> CImgDisplay& render(const CImg<T>& 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(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) |
| throw CImgArgumentException("CImgDisplay::assign() : Specified window size (%u,%u) is not valid.",dimw,dimh); |
| assign_lowlevel(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<typename T> CImgDisplay& assign(const CImg<T>& 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.is_empty()) |
| throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input image (%u,%u,%u,%u,%p) is empty.", |
| img.width,img.height,img.depth,img.dim,img.data); |
| CImg<T> tmp; |
| const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); |
| assign_lowlevel(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<typename T> CImgDisplay& assign(const CImgList<T>& 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.is_empty()) |
| throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input list (%u,%p) is empty.", |
| list.size,list.data); |
| CImg<T> tmp; |
| const CImg<T> img = list.get_append('x'), |
| &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); |
| assign_lowlevel(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) { |
| assign_lowlevel(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(); |
| } |
| |
| CImgDisplay& _assign() { |
| if (width && height) { |
| pthread_mutex_lock(cimg::X11attr().mutex); |
| |
| // Remove display window from event thread list |
| unsigned int i; |
| for (i=0; i<cimg::X11attr().nb_wins && cimg::X11attr().wins[i]!=this; i++); |
| for (; i<cimg::X11attr().nb_wins-1; i++) cimg::X11attr().wins[i]=cimg::X11attr().wins[i+1]; |
| cimg::X11attr().nb_wins--; |
| |
| // Destroy window, image, colormap and title |
| if (is_fullscreen) _desinit_fullscreen(); |
| XDestroyWindow(cimg::X11attr().display,window); |
| window = 0; |
| #ifdef cimg_use_xshm |
| if (shminfo) { |
| XShmDetach(cimg::X11attr().display, shminfo); |
| XDestroyImage(image); |
| shmdt(shminfo->shmaddr); |
| 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; |
| } |
| |
| template<typename T> CImgDisplay& display(const CImg<T>& img) { |
| return render(img).paint(false); |
| } |
| |
| CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { |
| if (!(nwidth && nheight)) |
| throw CImgArgumentException("CImgDisplay::resize() : Specified window size (%d,%d) is not valid.", |
| nwidth,nheight); |
| const unsigned int |
| tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100), |
| tmpdimy=(nheight>0)?nheight:(-nheight*height/100), |
| dimx = tmpdimx?tmpdimx:1, |
| dimy = tmpdimy?tmpdimy:1; |
| 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) { |
| 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() { |
| 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() { |
| pthread_mutex_lock(cimg::X11attr().mutex); |
| XDefineCursor(cimg::X11attr().display,window,None); |
| pthread_mutex_unlock(cimg::X11attr().mutex); |
| return *this; |
| } |
| |
| static void wait_all() { |
| pthread_mutex_lock(cimg::X11attr().mutex); |
| bool flag = true; |
| XEvent event; |
| while (flag) { |
| for (unsigned int i=0; i<cimg::X11attr().nb_wins; i++) { |
| cimg::X11attr().wins[i]->is_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; i<cimg::X11attr().nb_wins; i++) |
| if (!cimg::X11attr().wins[i]->is_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_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_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,...) { |
| 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) { |
| pthread_mutex_lock(cimg::X11attr().mutex); |
| _paint(wait_expose); |
| pthread_mutex_unlock(cimg::X11attr().mutex); |
| return *this; |
| } |
| |
| template<typename T> CImgDisplay& render(const CImg<T>& img, const bool flag8=false) { |
| if (img.is_empty()) |
| 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<T>::id()==cimg::type<unsigned char>::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<xymax; xy++) (*ptrd++) = (unsigned char)*(data1++); |
| break; |
| case 2: for (unsigned int xy=0; xy<xymax; xy++) { |
| const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++); |
| (*ptrd++) = (R&0xf0)|(G>>4); |
| } break; |
| default: for (unsigned int xy=0; xy<xymax; xy++) { |
| const unsigned char R = (unsigned char)*(data1++), G = (unsigned char)*(data2++), B = (unsigned char)*(data3++); |
| (*ptrd++) = (R&0xe0) | ((G>>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<xymax; xy++) { |
| const unsigned char G = (unsigned char)*(data2++)>>2; |
| *(ptrd++) = (unsigned char)*(data1++)&M | (G>>3); |
| *(ptrd++) = (G<<5) | ((unsigned char)*(data3++)>>3); |
| } else for (unsigned int xy=0; xy<xymax; xy++) { |
| const unsigned char G = (unsigned char)*(data2++)>>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<xymax; xy++) { |
| *(ptrd++) = 0; |
| *(ptrd++) = (unsigned char)*(data1++); |
| *(ptrd++) = (unsigned char)*(data2++); |
| *(ptrd++) = (unsigned char)*(data3++); |
| } else for (unsigned int xy=0; xy<xymax; xy++) { |
| *(ptrd++) = (unsigned char)*(data3++); |
| *(ptrd++) = (unsigned char)*(data2++); |
| *(ptrd++) = (unsigned char)*(data1++); |
| *(ptrd++) = 0; |
| } |
| if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; } |
| } break; |
| }; |
| } else { |
| if (normalization==3) { |
| if (cimg::type<T>::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } |
| else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::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<xymax; xy++) { |
| const unsigned char R = (unsigned char)(255*(*(data1++)-min)/mm); |
| *(ptrd++) = R; |
| } break; |
| case 2: for (unsigned int xy=0; xy<xymax; xy++) { |
| const unsigned char |
| R = (unsigned char)(255*(*(data1++)-min)/mm), |
| G = (unsigned char)(255*(*(data2++)-min)/mm); |
| (*ptrd++) = (R&0xf0) | (G>>4); |
| } break; |
| default: |
| for (unsigned int xy=0; xy<xymax; 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&0xe0) | ((G>>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<xymax; xy++) { |
| const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>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<xymax; xy++) { |
| const unsigned char G = (unsigned char)(255*(*(data2++)-min)/mm)>>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; xy<xymax; xy++) { |
| (*ptrd++) = 0; |
| (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm); |
| (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm); |
| (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm); |
| } else for (unsigned int xy=0; xy<xymax; xy++) { |
| (*ptrd++) = (unsigned char)(255*(*(data3++)-min)/mm); |
| (*ptrd++) = (unsigned char)(255*(*(data2++)-min)/mm); |
| (*ptrd++) = (unsigned char)(255*(*(data1++)-min)/mm); |
| (*ptrd++) = 0; |
| } |
| if (ndata!=data) { _render_resize(ndata,img.width,img.height,(unsigned int*)data,width,height); delete[] ndata; } |
| } break; |
| } |
| } |
| |
| pthread_mutex_unlock(cimg::X11attr().mutex); |
| return *this; |
| } |
| |
| static int _assign_lowlevel_xshm(Display *dpy, XErrorEvent *error) { |
| dpy = 0; error = 0; |
| cimg::X11attr().shm_enabled = false; |
| return 0; |
| } |
| |
| void assign_lowlevel(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 display window if existing |
| if (width && height) _assign(); |
| |
| // Open X11 display if necessary. |
| if (!cimg::X11attr().display) { |
| cimg::X11attr().nb_wins = 0; |
| cimg::X11attr().mutex = new pthread_mutex_t; |
| pthread_mutex_init(cimg::X11attr().mutex,0); |
| |
| cimg::X11attr().display = XOpenDisplay((std::getenv("DISPLAY") ? std::getenv("DISPLAY") : ":0.0")); |
| if (!cimg::X11attr().display) |
| throw CImgDisplayException("CImgDisplay::_create_window() : Can't open X11 display"); |
| cimg::X11attr().nb_bits = DefaultDepth(cimg::X11attr().display, DefaultScreen(cimg::X11attr().display)); |
| if (cimg::X11attr().nb_bits!=8 && cimg::X11attr().nb_bits!=16 && cimg::X11attr().nb_bits!=24 && cimg::X11attr().nb_bits!=32) |
| throw CImgDisplayException("CImgDisplay::_create_window() : %u bits mode is not supported " |
| "(only 8, 16, 24 and 32 bits modes are supported)",cimg::X11attr().nb_bits); |
| cimg::X11attr().gc = new GC; |
| *cimg::X11attr().gc = DefaultGC(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); |
| Visual *visual = DefaultVisual(cimg::X11attr().display,DefaultScreen(cimg::X11attr().display)); |
| XVisualInfo vtemplate; |
| vtemplate.visualid = XVisualIDFromVisual(visual); |
| int nb_visuals; |
| XVisualInfo *vinfo = XGetVisualInfo(cimg::X11attr().display,VisualIDMask,&vtemplate,&nb_visuals); |
| if (vinfo && vinfo->red_mask<vinfo->blue_mask) cimg::X11attr().blue_first = true; |
| cimg::X11attr().byte_order = ImageByteOrder(cimg::X11attr().display); |
| |
| 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 = dimw; |
| height = dimh; |
| 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) { XDestroyImage(image); shmctl(shminfo->shmid,IPC_RMID,0); delete shminfo; shminfo = 0; } |
| shminfo->readOnly = False; |
| cimg::X11attr().shm_enabled = true; |
| XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_lowlevel_xshm); |
| XShmAttach(cimg::X11attr().display, shminfo); |
| XSync(cimg::X11attr().display, False); |
| XSetErrorHandler(oldXErrorHandler); |
| if (!cimg::X11attr().shm_enabled) { |
| XDestroyImage(image); |
| shmdt(shminfo->shmaddr); |
| shmctl(shminfo->shmid,IPC_RMID,0); |
| 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<int>::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 { |
| #if 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<typename T> 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); |
| nshminfo->shmid = shmget(IPC_PRIVATE, ndimx*ndimy*sizeof(T), IPC_CREAT | 0777); |
| nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0); |
| nshminfo->readOnly = False; |
| XShmAttach(cimg::X11attr().display, nshminfo); |
| XSync(cimg::X11attr().display, False); |
| 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<cimg::X11attr().nb_resolutions; i++) { |
| const unsigned int |
| nw = (unsigned int)(cimg::X11attr().resolutions[i].width), |
| nh = (unsigned int)(cimg::X11attr().resolutions[i].height); |
| if (nw>=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); |
| 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); |
| #if 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; i<cimg::X11attr().nb_wins; i++) { |
| 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); |
| } |
| 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; i<cimg::X11attr().nb_wins; i++) |
| if (!cimg::X11attr().wins[i]->is_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(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) |
| throw CImgArgumentException("CImgDisplay::assign() : Specified window size (%u,%u) is not valid.",dimw,dimh); |
| assign_lowlevel(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<typename T> CImgDisplay& assign(const CImg<T>& 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.is_empty()) |
| throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input image (%u,%u,%u,%u,%p) is empty.", |
| img.width,img.height,img.depth,img.dim,img.data); |
| CImg<T> tmp; |
| const CImg<T>& nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); |
| assign_lowlevel(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<typename T> CImgDisplay& assign(const CImgList<T>& 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.is_empty()) |
| throw CImgArgumentException("CImgDisplay::CImgDisplay() : Specified input list (%u,%p) is empty.", |
| list.size,list.data); |
| CImg<T> tmp; |
| const CImg<T> img = list.get_append('x'), |
| &nimg = (img.depth==1)?img:(tmp=img.get_projections2d(img.width/2,img.height/2,img.depth/2)); |
| assign_lowlevel(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) { |
| assign_lowlevel(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(); |
| } |
| |
| CImgDisplay& _assign() { |
| 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; |
| } |
| |
| template<typename T> CImgDisplay& display(const CImg<T>& img) { |
| return render(img).paint(); |
| } |
| |
| CImgDisplay& resize(const int nwidth, const int nheight, const bool redraw=true) { |
| if (!(nwidth && nheight)) |
| throw CImgArgumentException("CImgDisplay::resize() : Specified window size (%d,%d) is not valid.", |
| nwidth,nheight); |
| const unsigned int |
| tmpdimx=(nwidth>0)?nwidth:(-nwidth*width/100), |
| tmpdimy=(nheight>0)?nheight:(-nheight*height/100), |
| dimx = tmpdimx?tmpdimx:1, |
| dimy = tmpdimy?tmpdimy:1; |
| 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_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(); |
| } |
| |
| // Internal routine to retrieve the position of the current window. |
| 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; |
| } |
| |
| 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() { |
| visible_cursor = false; |
| ShowCursor(FALSE); |
| SendMessage(window,WM_SETCURSOR,0,0); |
| return *this; |
| } |
| |
| CImgDisplay& show_mouse() { |
| 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_closed) { |
| is_closed = false; |
| if (is_fullscreen) _init_fullscreen(); |
| ShowWindow(window,SW_SHOW); |
| _update_window_pos(); |
| } |
| return paint(); |
| } |
| |
| CImgDisplay& close() { |
| 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,...) { |
| 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<typename T> CImgDisplay& render(const CImg<T>& img) { |
| if (img.is_empty()) |
| 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<T>::id()==cimg::type<unsigned char>::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<T>::is_float()) { const CImgStats st(img,false); min = (float)st.min; max = (float)st.max; } |
| else { min = (float)cimg::type<T>::min(); max = (float)cimg::type<T>::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_lowlevel(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 (width && height) _assign(); |
| |
| // Set display variables |
| width = dimw; |
| height = dimh; |
| 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; |
| } |
| } |
| |
| #endif |
| |
| }; |
| |
| /* |
| #-------------------------------------- |
| # |
| # |
| # |
| # Definition of the CImg<T> 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<T>, 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 <tt>(x,y,z)</tt>, 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<T> rather than simple images \ref CImg<T>. |
| |
| Thus, the \ref CImg<T> 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<T> 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 : <tt>unsigned char, char, short, unsigned int, int, |
| unsigned long, long, float, double, ... </tt>. |
| Typically, fast image display can be done using <tt>CImg<unsigned char></tt> images, |
| while complex image processing algorithms may be rather coded using <tt>CImg<float></tt> or <tt>CImg<double></tt> |
| 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 : |
| - <tt>CImg<char> img;</tt> declares an empty image. |
| - <tt>CImg<unsigned char> img(128,128);</tt> declares a 128x128 greyscale image with |
| \c unsigned \c char pixel values. |
| - <tt>CImg<double> img(3,3);</tt> declares a 3x3 matrix with \c double coefficients. |
| - <tt>CImg<unsigned char> img(256,256,1,3);</tt> declares a 256x256x1x3 (color) image |
| (colors are stored as an image with three channels). |
| - <tt>CImg<double> img(128,128,128);</tt> declares a 128x128x128 volumetric and greyscale image |
| (with \c double pixel values). |
| - <tt>CImg<> img(128,128,128,3);</tt> 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 <b>not automatically initialized to 0</b>. You may use the function \ref fill() to |
| do it, or use the specific constructor taking 5 parameters like this : |
| <tt>CImg<> img(128,128,128,3,0);</tt> declares a 128x128x128 volumetric color image with all pixel values to 0. |
| |
| - Construct images from filenames : |
| - <tt>CImg<unsigned char> img("image.jpg");</tt> reads a JPEG color image from the file "image.jpg". |
| - <tt>CImg<float> img("analyze.hdr");</tt> reads a volumetric image (ANALYZE7.5 format) from the file "analyze.hdr". |
| - \b Note : You need to install <a href="http://www.imagemagick.org">ImageMagick</a> |
| to be able to read common compressed image formats (JPG,PNG,...) (See \ref cimg_files_io). |
| |
| - Construct images from C-style arrays : |
| - <tt>CImg<int> img(data_buffer,256,256);</tt> constructs a 256x256 greyscale image from a \c int* buffer |
| \c data_buffer (of size 256x256=65536). |
| - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,false);</tt> constructs a 256x256 color image |
| from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). |
| - <tt>CImg<unsigned char> img(data_buffer,256,256,1,3,true);</tt> 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 <a href="#constructors">here</a>. |
| |
| \par Most useful functions |
| |
| The \ref CImg<T> 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<typename T> struct CImg { |
| |
| //! Variable representing the width of the instance image (i.e. dimensions along the X-axis). |
| /** |
| \remark |
| - Prefer using the function CImg<T>::dimx() to get information about the width of an image. |
| - Use function CImg<T>::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<T>::dimy() to get information about the height of an image. |
| - Use function CImg<T>::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<T>::dimz() to get information about the depth of an image. |
| - Use function CImg<T>::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<T>::dimv() to get information about the depth of an image. |
| - Use function CImg<T>::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<T>. |
| /** |
| \remark |
| - An \p iterator is a <tt>T*</tt> 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<T>. |
| /** |
| \remark |
| - A \p const_iterator is a <tt>const T*</tt> 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<typename t> CImg(const CImg<t>& 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<T*>(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<typename t> CImg& assign(const CImg<t>& 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<typename t> CImg(const CImg<t>& 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<t>::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<T*>(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<typename t> CImg& assign(const CImg<t>& 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<typename t> 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<t>::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<T*>(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; } |
| } |
| |
| template<typename t> CImg(const t *const data_buffer, const unsigned int dx, const unsigned int dy=1, const unsigned int dz=1) { |
| |
| } |
| |
| //! In-place version of the previous constructor. |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> 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<typename t> 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<typename t> 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<t>::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<T*>(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 (<tt>"unsigned char"</tt>). |
| - If the template parameter T does not correspond to a registered type, the string <tt>"unknown"</tt> is returned. |
| **/ |
| static const char* pixel_type() { |
| return cimg::type<T>::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<typename t> bool is_sameX(const CImg<t>& 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<typename t> bool is_sameY(const CImg<t>& 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<typename t> bool is_sameZ(const CImg<t>& img) const { |
| return (depth==img.depth); |
| } |
| |
| //! Return \c true if images \c (*this) and \c img have same dim. |
| template<typename t> bool is_sameV(const CImg<t>& img) const { |
| return (dim==img.dim); |
| } |
| |
| //! Return \c true if images have same width and same height. |
| template<typename t> bool is_sameXY(const CImg<t>& 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<typename t> bool is_sameXYZ(const CImg<t>& 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<typename t> bool is_sameXYZV(const CImg<t>& 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); |
| } |
| |
| //! 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<float> 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<float> 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=%d) 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<float> 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=%d) " |
| "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=%d) " |
| "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=%d) " |
| "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=%d) " |
| "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<float> 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<float> 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<float> 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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<T,float>::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<width?x+1:width-1, ax = nx+1<width?nx+1:width-1; |
| const float dx = fx-x; |
| const T& a = (*this)(px,y,z,v), b = (*this)(x,y,z,v), c = (*this)(nx,y,z,v), d = (*this)(ax,y,z,v); |
| 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; |
| } |
| |
| //! Read a pixel value using bicubic interpolation. |
| /** |
| \param pfx X-coordinate of the pixel (float-valued). |
| \param pfy Y-coordinate of the pixel (float-valued). |
| \param z Z-coordinate of the pixel. |
| \param v V-coordinate of the pixel. |
| |
| - This function allows to read pixel values with boundary checking on the two first 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 cubic interpolation is performed in order to compute the returned value. |
| |
| \sa operator()(), cubic_pix1d(), linear_pix2d(). |
| **/ |
| typename cimg::largest<T,float>::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<T,float>::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<width?x+1:width-1, ax = nx+1<width?nx+1:width-1, |
| y = (unsigned int)fy, py = (int)y-1>=0?y-1:0, ny = y+1<height?y+1:height-1, ay = ny+1<height?ny+1:height-1; |
| const float dx = fx-x, dy = fy-y; |
| const T& |
| a = (*this)(px,py,z,v), b = (*this)(x,py,z,v), c = (*this)(nx,py,z,v), d = (*this)(ax,py,z,v), |
| e = (*this)(px, y,z,v), f = (*this)(x, y,z,v), g = (*this)(nx, y,z,v), h = (*this)(ax, y,z,v), |
| i = (*this)(px,ny,z,v), j = (*this)(x,ny,z,v), k = (*this)(nx,ny,z,v), l = (*this)(ax,ny,z,v), |
| m = (*this)(px,ay,z,v), n = (*this)(x,ay,z,v), o = (*this)(nx,ay,z,v), p = (*this)(ax,ay,z,v); |
| 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; |
| } |
| |
| //! Display informations about the image on the standard error output. |
| /** |
| \param title Name for the considered image (optional). |
| \param print_flag Level of informations to be printed. |
| |
| - The possible values for \c print_flag are : |
| - 0 : print only informations about image size and pixel buffer. |
| - 1 : print also statistics on the image pixels. |
| - 2 : print also the content of the pixel buffer, in a matlab-style. |
| |
| \par example: |
| \code |
| CImg<float> 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 standart output. |
| const CImg& print(const unsigned int print_flag) const { |
| return print(0,print_flag); |
| } |
| |
| //@} |
| //------------------------------------------ |
| // |
| //! \name Arithmetic and Boolean Operators |
| //@{ |
| //------------------------------------------ |
| |
| //! Assignement 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<typename t> CImg<T>& operator=(const CImg<t>& 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) <tt>this->size()</tt>. |
| |
| - 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<float> 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<T>(*this,false); |
| } |
| |
| //! Operator+=; |
| #ifdef cimg_use_visualcpp6 |
| CImg& operator+=(const T& val) { |
| #else |
| template<typename t> CImg& operator+=(const t& val) { |
| #endif |
| cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)+val); |
| return *this; |
| } |
| |
| //! Operator+= |
| template<typename t> CImg& operator+=(const CImg<t>& 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<T>(width,height,depth,dim,0)-=*this; |
| } |
| |
| //! Operator-=. |
| #ifdef cimg_use_visualcpp6 |
| CImg& operator-=(const T& val) { |
| #else |
| template<typename t> CImg& operator-=(const t& val) { |
| #endif |
| cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)-val); |
| return *this; |
| } |
| |
| //! Operator-=. |
| template<typename t> CImg& operator-=(const CImg<t>& 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*=. |
| #ifdef cimg_use_visualcpp6 |
| CImg& operator*=(const double val) { |
| #else |
| template<typename t> CImg& operator*=(const t& val) { |
| #endif |
| cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)*val); |
| return *this; |
| } |
| |
| //! Operator*=. |
| template<typename t> CImg& operator*=(const CImg<t>& img) { |
| return ((*this)*img).swap(*this); |
| } |
| |
| //! Operator/=. |
| #ifdef cimg_use_visualcpp6 |
| CImg& operator/=(const double val) { |
| #else |
| template<typename t> CImg& operator/=(const t& val) { |
| #endif |
| cimg_for(*this,ptr,T) (*ptr)=(T)((*ptr)/val); |
| return *this; |
| } |
| |
| //! Operator/=. |
| template<typename t> CImg& operator/=(const CImg<t>& 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)%=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; *(--ptrd)%=*(--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; *(--ptrd)&=*(--ptrs)); |
| return *this; |
| } |
| |
| //! In-place bitwise AND. |
| CImg& operator&=(const T& val) { |
| cimg_for(*this,ptr,T) (*ptr)&=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; *(--ptrd)|=*(--ptrs)); |
| return *this; |
| } |
| |
| //! In-place bitwise OR. |
| CImg& operator|=(const T& val) { |
| cimg_for(*this,ptr,T) (*ptr)|=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; *(--ptrd)^=*(--ptrs)); |
| return *this; |
| } |
| |
| //! In-place bitwise XOR. |
| CImg& operator^=(const T& val) { |
| cimg_for(*this,ptr,T) (*ptr)^=val; |
| return *this; |
| } |
| |
| //! Boolean NOT. |
| CImg operator!() const { |
| CImg<T> res(width,height,depth,dim); |
| const T *ptrs = end(); |
| cimg_for(res,ptrd,T) *ptrd=!(*(--ptrs)); |
| return res; |
| } |
| |
| //! Bitwise NOT. |
| CImg operator~() const { |
| CImg<T> res(width,height,depth,dim); |
| const T *ptrs = end(); |
| cimg_for(res,ptrd,T) *ptrd=~(*(--ptrs)); |
| return res; |
| } |
| |
| //! Bitwise shift |
| CImg& operator<<=(const unsigned int n) { |
| cimg_for(*this,ptr,T) (*ptr)<<=n; |
| return *this; |
| } |
| |
| //! Bitwise shift |
| CImg operator<<(const unsigned int n) const { |
| return (+*this)<<=n; |
| } |
| |
| //! Bitwise shift |
| CImg& operator>>=(const unsigned int n) { |
| cimg_for(*this,ptr,T) (*ptr)>>=n; |
| return *this; |
| } |
| |
| //! Bitwise shift |
| CImg operator>>(const unsigned int n) const { |
| return (+*this)>>=n; |
| } |
| |
| //! Boolean equality. |
| template<typename t> bool operator==(const CImg<t>& 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<typename t> bool operator!=(const CImg<t>& img) const { |
| return !((*this)==img); |
| } |
| |
| //! Get a new list |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> operator<<(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this,img); |
| } |
| |
| //@} |
| //--------------------------------------- |
| // |
| //! \name Usual Mathematics |
| //@{ |
| //--------------------------------------- |
| |
| //! Apply a R->R function on all image value. |
| template<typename ts, typename td> CImg& apply(td (*func)(ts)) { |
| cimg_for(*this,ptr,T) *ptr = (T)func(*ptr); |
| return *this; |
| } |
| |
| //! Return an image where each pixel value is equal to func(x). |
| template<typename ts, typename td> CImg<typename cimg::largest<T,td>::type> get_apply(td (*func)(ts)) { |
| typedef typename cimg::largest<T,td>::type restype; |
| return CImg<restype>(*this,false).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<typename t> CImg& mul(const CImg<t>& img) { |
| t *ptrs = img.data; |
| T *ptrf = data + cimg::min(size(),img.size()); |
| for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd*(*(ptrs++))); |
| return *this; |
| } |
| |
| //! Pointwise multiplication between \c *this and \c img. |
| /** |
| \param img Argument of the multiplication. |
| - if \c *this and \c img have different size, the multiplication is applied on the maximum possible range. |
| \sa get_div(),mul(),div() |
| **/ |
| template<typename t> CImg<typename cimg::largest<T,t>::type> get_mul(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImg<restype>(*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<typename t> CImg& div(const CImg<t>& img) { |
| t *ptrs = img.data; |
| T *ptrf = data + cimg::min(size(),img.size()); |
| for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)(*ptrd/(*(ptrs++))); |
| return *this; |
| } |
| |
| //! Return an image from a pointwise division between \p *this and \p img. |
| /** |
| \param img = argument of the division. |
| \note if \c *this and \c img have different size, the division is applied |
| only on possible values. |
| \see get_mul(),mul(),div() |
| **/ |
| template<typename t> CImg<typename cimg::largest<T,t>::type> get_div(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImg<restype>(*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<typename t> CImg& max(const CImg<t>& img) { |
| t *ptrs = img.data; |
| T *ptrf = data + cimg::min(size(),img.size()); |
| for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::max((T)*(ptrs++),*ptrd); |
| return *this; |
| } |
| |
| //! Return the image corresponding to the max value for each pixel. |
| /** |
| \param img = second argument of the max operator (the first one is *this). |
| \see max(), min(), get_min() |
| **/ |
| template<typename t> CImg<typename cimg::largest<T,t>::type> get_max(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImg<restype>(*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(). |
| **/ |
| #ifdef cimg_use_visualcpp6 |
| CImg& max(const T val) { |
| #else |
| CImg& max(const T& val) { |
| #endif |
| 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() |
| **/ |
| #ifdef cimg_use_visualcpp6 |
| CImg get_max(const T val) const { |
| #else |
| CImg get_max(const T& val) const { |
| #endif |
| 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<typename t> CImg& min(const CImg<t>& img) { |
| t *ptrs = img.data; |
| T *ptrf = data + cimg::min(size(),img.size()); |
| for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=cimg::min((T)*(ptrs++),*ptrd); |
| return *this; |
| } |
| //! Return the image corresponding to the min value for each pixel. |
| /** |
| \param img = second argument of the min operator (the first one is *this). |
| \see min(), max(), get_max() |
| **/ |
| template<typename t> CImg<typename cimg::largest<T,t>::type> get_min(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImg<restype>(*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(). |
| **/ |
| #ifdef cimg_use_visualcpp6 |
| CImg& min(const T val) { |
| #else |
| CImg& min(const T& val) { |
| #endif |
| 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() |
| **/ |
| #ifdef cimg_use_visualcpp6 |
| CImg get_min(const T val) const { |
| #else |
| CImg get_min(const T& val) const { |
| #endif |
| 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<typename cimg::largest<T,float>::type> get_sqrt() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_exp() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_log() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_log10() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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==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<typename cimg::largest<T,float>::type> get_pow(const double p) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename t> CImg& pow(const CImg<t>& img) { |
| t *ptrs = img.data; |
| T *ptrf = data + cimg::min(size(),img.size()); |
| for (T* ptrd = data; ptrd<ptrf; ptrd++) (*ptrd)=(T)std::pow((double)*ptrd,(double)(*(ptrs++))); |
| return *this; |
| } |
| |
| //! Return each image pixel (*this)(x,y,z,k) by its power by \p img(x,y,z,k) |
| template<typename t> CImg<typename cimg::largest<T,float>::type> get_pow(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_abs() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_cos() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_sin() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_tan() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_acos() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_asin() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_atan() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*this,false).atan(); |
| } |
| |
| //! Return the MSE (Mean-Squared Error) between two images. |
| template<typename t> double MSE(const CImg<t>& 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<typename t> double PSNR(const CImg<t>& img, const double valmax=255.0) const { |
| const double vMSE = std::sqrt(MSE(img)); |
| return (vMSE!=0)?(20*std::log10(valmax/vMSE)):(cimg::type<double>::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; ptr<ptr_end; ) { *(ptr++)=val0; *(ptr++)=val1; } |
| if (ptr!=ptr_end+1) *(ptr++)=val0; |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1) const { |
| return (+*this).fill(val0,val1); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-2; |
| for (ptr=data; ptr<ptr_end; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; } |
| ptr_end+=2; |
| switch (ptr_end-ptr) { |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2) const { |
| return (+*this).fill(val0,val1,val2); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-3; |
| for (ptr=data; ptr<ptr_end; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; } |
| ptr_end+=3; |
| switch (ptr_end-ptr) { |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const { |
| return (+*this).fill(val0,val1,val2,val3); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-4; |
| for (ptr=data; ptr<ptr_end; ) { *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; } |
| ptr_end+=4; |
| switch (ptr_end-ptr) { |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const { |
| return (+*this).fill(val0,val1,val2,val3,val4); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5 |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4,const T& val5) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-5; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; |
| } |
| ptr_end+=5; |
| switch (ptr_end-ptr) { |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a val4 and \a val5 |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3, |
| const T& val4,const T& val5,const T& val6) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-6; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6; |
| } |
| ptr_end+=6; |
| switch (ptr_end-ptr) { |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val7. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3, |
| const T& val4,const T& val5,const T& val6,const T& val7) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-7; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; |
| *(ptr++)=val4; *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; |
| } |
| ptr_end+=7; |
| switch (ptr_end-ptr) { |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val8. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2, |
| const T& val3,const T& val4,const T& val5, |
| const T& val6,const T& val7,const T& val8) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-8; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; |
| *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; |
| *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; |
| } |
| ptr_end+=8; |
| switch (ptr_end-ptr) { |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7, const T& val8) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val9. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| \param val9 = fill value 10 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4, |
| const T& val5,const T& val6,const T& val7,const T& val8,const T& val9) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-9; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; |
| *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; |
| } |
| ptr_end+=9; |
| switch (ptr_end-ptr) { |
| case 9: *(--ptr_end)=val8; |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7, const T& val8, const T& val9) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val11. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| \param val9 = fill value 10 |
| \param val10 = fill value 11 |
| \param val11 = fill value 12 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3, |
| const T& val4,const T& val5,const T& val6,const T& val7, |
| const T& val8,const T& val9,const T& val10,const T& val11) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-11; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; |
| *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11; |
| } |
| ptr_end+=11; |
| switch (ptr_end-ptr) { |
| case 11: *(--ptr_end)=val10; |
| case 10: *(--ptr_end)=val9; |
| case 9: *(--ptr_end)=val8; |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val11. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| \param val9 = fill value 10 |
| \param val10 = fill value 11 |
| \param val11 = fill value 12 |
| \param val12 = fill value 13 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3, |
| const T& val4,const T& val5,const T& val6,const T& val7, |
| const T& val8,const T& val9,const T& val10,const T& val11, |
| const T& val12) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-12; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; |
| *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11; |
| *(ptr++)=val12; |
| } |
| ptr_end+=12; |
| switch (ptr_end-ptr) { |
| case 12: *(--ptr_end)=val11; |
| case 11: *(--ptr_end)=val10; |
| case 10: *(--ptr_end)=val9; |
| case 9: *(--ptr_end)=val8; |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, |
| const T& val12, const T& val13) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13); |
| } |
| |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val15. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| \param val9 = fill value 10 |
| \param val10 = fill value 11 |
| \param val11 = fill value 12 |
| \param val12 = fill value 13 |
| \param val13 = fill value 14 |
| \param val14 = fill value 15 |
| \param val15 = fill value 16 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3, |
| const T& val4,const T& val5,const T& val6,const T& val7, |
| const T& val8,const T& val9,const T& val10,const T& val11, |
| const T& val12,const T& val13,const T& val14,const T& val15) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-15; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; *(ptr++)=val5; |
| *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; *(ptr++)=val10; *(ptr++)=val11; |
| *(ptr++)=val12; *(ptr++)=val13; *(ptr++)=val14; *(ptr++)=val15; |
| } |
| ptr_end+=15; |
| switch (ptr_end-ptr) { |
| case 15: *(--ptr_end)=val14; |
| case 14: *(--ptr_end)=val13; |
| case 13: *(--ptr_end)=val12; |
| case 12: *(--ptr_end)=val11; |
| case 11: *(--ptr_end)=val10; |
| case 10: *(--ptr_end)=val9; |
| case 9: *(--ptr_end)=val8; |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, |
| const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, |
| const T& val12, const T& val13, const T& val14, const T& val15) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10,val11,val12,val13,val14,val15); |
| } |
| |
| //! Fill sequentially all pixel values with values \a val0 and \a val1 and \a val2 and \a val3 and \a ... and \a val24. |
| /** |
| \param val0 = fill value 1 |
| \param val1 = fill value 2 |
| \param val2 = fill value 3 |
| \param val3 = fill value 4 |
| \param val4 = fill value 5 |
| \param val5 = fill value 6 |
| \param val6 = fill value 7 |
| \param val7 = fill value 8 |
| \param val8 = fill value 9 |
| \param val9 = fill value 10 |
| \param val10 = fill value 11 |
| \param val11 = fill value 12 |
| \param val12 = fill value 13 |
| \param val13 = fill value 14 |
| \param val14 = fill value 15 |
| \param val15 = fill value 16 |
| \param val16 = fill value 17 |
| \param val17 = fill value 18 |
| \param val18 = fill value 19 |
| \param val19 = fill value 20 |
| \param val20 = fill value 21 |
| \param val21 = fill value 22 |
| \param val22 = fill value 23 |
| \param val23 = fill value 24 |
| \param val24 = fill value 25 |
| **/ |
| CImg& fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4, |
| const T& val5,const T& val6,const T& val7,const T& val8,const T& val9, |
| const T& val10,const T& val11,const T& val12,const T& val13,const T& val14, |
| const T& val15,const T& val16,const T& val17,const T& val18,const T& val19, |
| const T& val20,const T& val21,const T& val22,const T& val23,const T& val24) { |
| if (!is_empty()) { |
| T *ptr, *ptr_end = end()-24; |
| for (ptr=data; ptr<ptr_end; ) { |
| *(ptr++)=val0; *(ptr++)=val1; *(ptr++)=val2; *(ptr++)=val3; *(ptr++)=val4; |
| *(ptr++)=val5; *(ptr++)=val6; *(ptr++)=val7; *(ptr++)=val8; *(ptr++)=val9; |
| *(ptr++)=val10; *(ptr++)=val11; *(ptr++)=val12; *(ptr++)=val13; *(ptr++)=val14; |
| *(ptr++)=val15; *(ptr++)=val16; *(ptr++)=val17; *(ptr++)=val18; *(ptr++)=val19; |
| *(ptr++)=val20; *(ptr++)=val21; *(ptr++)=val22; *(ptr++)=val23; *(ptr++)=val24; |
| } |
| ptr_end+=24; |
| switch (ptr_end-ptr) { |
| case 24: *(--ptr_end)=val23; |
| case 23: *(--ptr_end)=val22; |
| case 22: *(--ptr_end)=val21; |
| case 21: *(--ptr_end)=val20; |
| case 20: *(--ptr_end)=val19; |
| case 19: *(--ptr_end)=val18; |
| case 18: *(--ptr_end)=val17; |
| case 17: *(--ptr_end)=val16; |
| case 16: *(--ptr_end)=val15; |
| case 15: *(--ptr_end)=val14; |
| case 14: *(--ptr_end)=val13; |
| case 13: *(--ptr_end)=val12; |
| case 12: *(--ptr_end)=val11; |
| case 11: *(--ptr_end)=val10; |
| case 10: *(--ptr_end)=val9; |
| case 9: *(--ptr_end)=val8; |
| case 8: *(--ptr_end)=val7; |
| case 7: *(--ptr_end)=val6; |
| case 6: *(--ptr_end)=val5; |
| case 5: *(--ptr_end)=val4; |
| case 4: *(--ptr_end)=val3; |
| case 3: *(--ptr_end)=val2; |
| case 2: *(--ptr_end)=val1; |
| case 1: *(--ptr_end)=val0; |
| } |
| } |
| return *this; |
| } |
| |
| CImg get_fill(const T& val0,const T& val1,const T& val2,const T& val3,const T& val4, |
| const T& val5,const T& val6,const T& val7,const T& val8,const T& val9, |
| const T& val10,const T& val11,const T& val12,const T& val13,const T& val14, |
| const T& val15,const T& val16,const T& val17,const T& val18,const T& val19, |
| const T& val20,const T& val21,const T& val22,const T& val23,const T& val24) const { |
| return (+*this).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9, |
| val10,val11,val12,val13,val14,val15,val16,val17,val18,val19, |
| val20,val21,val22,val23,val24); |
| } |
| |
| //! Linear normalization of the pixel values between \a a and \a b. |
| /** |
| \param a = minimum pixel value after normalization. |
| \param b = maximum pixel value after normalization. |
| \see get_normalize(), cut(), get_cut(). |
| **/ |
| CImg& normalize(const T& a, const T& b) { |
| if (!is_empty()) { |
| const CImgStats st(*this,false); |
| if (st.min==st.max) return fill(0); |
| if (st.min!=a || st.max!=b) cimg_for(*this,ptr,T) *ptr=(T)((*ptr-st.min)/(st.max-st.min)*(b-a)+a); |
| } |
| return *this; |
| } |
| |
| //! Return the image of normalized values. |
| /** |
| \param a = minimum pixel value after normalization. |
| \param b = maximum pixel value after normalization. |
| \see normalize(), cut(), get_cut(). |
| **/ |
| CImg get_normalize(const T& a, const T& b) const { |
| return (+*this).normalize(a,b); |
| } |
| |
| //! Cut pixel values between \a a and \a b. |
| /** |
| \param a = minimum pixel value after cut. |
| \param b = maximum pixel value after cut. |
| \see get_cut(), normalize(), get_normalize(). |
| **/ |
| CImg& cut(const T& a, const T& b) { |
| if (!is_empty()) |
| cimg_for(*this,ptr,T) *ptr = (*ptr<a)?a:((*ptr>b)?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<T>(); |
| 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),width), |
| cimg::mod((int)(h2 - (x-dw2)*sa + (y-dh2)*ca),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<T>(); |
| 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<ymax; y++) for (unsigned int x=xmin; x<xmax; x++) |
| dest(x,y,z,v) = (*this)(y-yoff,height-1-x+xoff,z,v); |
| } break; |
| case 2: { |
| cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = (*this)(width-1-x,height-1-y,z,v); |
| } break; |
| case 3: { |
| 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<ymax; y++) for (unsigned int x=xmin; x<xmax; x++) |
| dest(x,y,z,v) = (*this)(width-1-y+yoff,x-xoff,z,v); |
| } break; |
| default: |
| return *this; |
| } |
| } else |
| switch (cond) { // generic version |
| case 0: { |
| cimg_forXY(dest,x,y) |
| cimg_forZV(*this,z,v) |
| dest(x,y,z,v) = pix2d((int)(cx + (x-cx)*ca + (y-cy)*sa),(int)(cy - (x-cx)*sa + (y-cy)*ca),z,v,0); |
| } break; |
| case 1: { |
| cimg_forXY(dest,x,y) |
| cimg_forZV(*this,z,v) |
| dest(x,y,z,v) = (*this)(cimg::mod((int)(cx + (x-cx)*ca + (y-cy)*sa),width), |
| cimg::mod((int)(cy - (x-cx)*sa + (y-cy)*ca),height),z,v); |
| } break; |
| case 2: { |
| cimg_forXY(dest,x,y) { |
| const float X = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*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 = cx + (x-cx)*ca + (y-cy)*sa, Y = cy - (x-cx)*sa + (y-cy)*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 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 |
| \note Rotation does not change the image size. If you want to get an image with a new size, use get_rotate() instead. |
| \see get_rotate() |
| **/ |
| CImg& rotate(const float angle,const float cx,const float cy,const float zoom=1,const unsigned int cond=3) { |
| return get_rotate(angle,cx,cy,zoom,cond).swap(*this); |
| } |
| |
| //! Return a resized 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 : additionnal 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 int pdx=-100, const int pdy=-100, const int pdz=-100, const int pdv=-100, |
| const unsigned int interp=1, const int border_condition=-1) const { |
| if (!pdx || !pdy || !pdz || !pdv) return CImg<T>(); |
| 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 (is_empty()) return CImg<T>(dx,dy,dz,dv,0); |
| if (width==dx && height==dy && depth==dz && dim==dv) return *this; |
| CImg res; |
| |
| switch (interp) { |
| 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; k<dv; ) { |
| const T *ptrz = ptrv; |
| poffz = offz; |
| for (unsigned int z=0; z<dz; ) { |
| const T *ptry = ptrz; |
| poffy = offy; |
| for (unsigned int y=0; y<dy; ) { |
| const T *ptrx = ptry; |
| poffx = offx; |
| cimg_forX(res,x) { *(ptrd++)=*ptrx; ptrx+=*(poffx++); } |
| y++; |
| unsigned int dy=*(poffy++); |
| for (;!dy && y<dy; std::memcpy(ptrd, ptrd-dx, sizeof(T)*dx), y++, ptrd+=dx, dy=*(poffy++)); |
| ptry+=dy; |
| } |
| z++; |
| unsigned int dz=*(poffz++); |
| for (;!dz && z<dz; std::memcpy(ptrd, ptrd-rwh, sizeof(T)*rwh), z++, ptrd+=rwh, dz=*(poffz++)); |
| ptrz+=dz; |
| } |
| k++; |
| unsigned int dv=*(poffv++); |
| for (;!dv && k<dv; std::memcpy(ptrd, ptrd-rwhd, sizeof(T)*rwhd), k++, ptrd+=rwhd, dv=*(poffv++)); |
| ptrv+=dv; |
| } |
| delete[] offx; delete[] offy; delete[] offz; delete[] offv; |
| } break; |
| |
| case 2: { // Mosaic filling |
| res.assign(dx,dy,dz,dv); |
| for (unsigned int k=0; k<dv; k+=dim) |
| for (unsigned int z=0; z<dz; z+=depth) |
| for (unsigned int y=0; y<dy; y+=height) |
| for (unsigned int x=0; x<dx; x+=width) res.draw_image(*this,x,y,z,k); |
| } break; |
| |
| case 3: { // Linear interpolation |
| const unsigned int dimmax = cimg::max(dx,dy,dz,dv); |
| const bool bborder = (interp>1 && border_condition<0); |
| const float |
| sx = bborder?(dx>0?(width-1.0f)/(dx-1) :0):(float)width/dx, |
| sy = bborder?(dy>0?(height-1.0f)/(dy-1):0):(float)height/dy, |
| sz = bborder?(dz>0?(depth-1.0f)/(dz-1) :0):(float)depth/dz, |
| sv = bborder?(dv>0?(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 = ptrs<ptrsmax?*(ptrs+1):(border_condition?val1:0); |
| *(ptrd++) = (T)((1-alpha)*val1 + alpha*val2); |
| ptrs+=*(poff++); |
| } |
| ptrs0+=width; |
| } |
| } |
| } else resx.assign(*this,true); |
| |
| if (dy!=height) { |
| if (height==1) resy = resx.get_resize(dx,dy,depth,dim,1,0); |
| else { |
| resy.assign(dx,dy,depth,dim); |
| curr = old = 0; poff = off; pfoff = foff; |
| cimg_forY(resy,y) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sy; *(poff++) = dx*((unsigned int)curr-(unsigned int)old); } |
| cimg_forXZV(resy,x,z,k) { |
| ptrd = resy.ptr(x,0,z,k); |
| const T *ptrs = resx.ptr(x,0,z,k), *const ptrsmax = ptrs + (height-1)*dx; |
| poff = off; pfoff = foff; |
| cimg_forY(resy,y) { |
| const float alpha = *(pfoff++); |
| const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+dx):(border_condition?val1:0); |
| *ptrd = (T)((1-alpha)*val1 + alpha*val2); |
| ptrd+=dx; |
| ptrs+=*(poff++); |
| } |
| } |
| } |
| resx.assign(); |
| } else resy.assign(resx,true); |
| |
| if (dz!=depth) { |
| if (depth==1) resz = resy.get_resize(dx,dy,dz,dim,1,0); |
| else { |
| const unsigned int wh = dx*dy; |
| resz.assign(dx,dy,dz,dim); |
| curr = old = 0; poff = off; pfoff = foff; |
| cimg_forZ(resz,z) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sz; *(poff++) = wh*((unsigned int)curr-(unsigned int)old); } |
| cimg_forXYV(resz,x,y,k) { |
| ptrd = resz.ptr(x,y,0,k); |
| const T *ptrs = resy.ptr(x,y,0,k), *const ptrsmax = ptrs + (depth-1)*wh; |
| poff = off; pfoff = foff; |
| cimg_forZ(resz,z) { |
| const float alpha = *(pfoff++); |
| const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+wh):(border_condition?val1:0); |
| *ptrd = (T)((1-alpha)*val1 + alpha*val2); |
| ptrd+=wh; |
| ptrs+=*(poff++); |
| } |
| } |
| } |
| resy.assign(); |
| } else resz.assign(resy,true); |
| |
| if (dv!=dim) { |
| if (dim==1) resv = resz.get_resize(dx,dy,dz,dv,1,0); |
| else { |
| const unsigned int whd = dx*dy*dz; |
| resv.assign(dx,dy,dz,dv); |
| curr = old = 0; poff = off; pfoff = foff; |
| cimg_forV(resv,k) { *(pfoff++) = curr-(unsigned int)curr; old = curr; curr+=sv; *(poff++) = whd*((unsigned int)curr-(unsigned int)old); } |
| cimg_forXYZ(resv,x,y,z) { |
| ptrd = resv.ptr(x,y,z,0); |
| const T *ptrs = resz.ptr(x,y,z,0), *const ptrsmax = ptrs + (dim-1)*whd; |
| poff = off; pfoff = foff; |
| cimg_forV(resv,k) { |
| const float alpha = *(pfoff++); |
| const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs+whd):(border_condition?val1:0); |
| *ptrd = (T)((1-alpha)*val1 + alpha*val2); |
| ptrd+=whd; |
| ptrs+=*(poff++); |
| } |
| } |
| } |
| resz.assign(); |
| } else resv.assign(resz,true); |
| |
| delete[] off; delete[] foff; |
| return resv.is_shared?(resz.is_shared?(resy.is_shared?(resx.is_shared?(+(*this)):resx):resy):resz):resv; |
| } break; |
| |
| case 4: { // Grid filling |
| res.assign(dx,dy,dz,dv,0); |
| cimg_forXYZV(*this,x,y,z,k) res(x*dx/width,y*dy/height,z*dz/depth,k*dv/dim) = (*this)(x,y,z,k); |
| } break; |
| |
| case 5: { // Cubic interpolation |
| const bool bborder = (interp>1 && border_condition<0); |
| const float |
| sx = bborder?(dx>0?(width-1.0f)/(dx-1) :0):(float)width/dx, |
| sy = bborder?(dy>0?(height-1.0f)/(dy-1):0):(float)height/dy, |
| sz = bborder?(dz>0?(depth-1.0f)/(dz-1) :0):(float)depth/dz, |
| sv = bborder?(dv>0?(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; |
| |
| } |
| |
| return res; |
| } |
| |
| //! Return a resized image. |
| /** |
| \param src = Image giving the geometry of the resize. |
| \param interp = Resizing type : |
| - 0 = no interpolation : additionnal 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<typename t> CImg get_resize(const CImg<t>& src, const unsigned 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 : additionnal 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 unsigned 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 : additionnal 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 unsigned 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; |
| 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 : additionnal 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<typename t> CImg& resize(const CImg<t>& src, const unsigned 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 : additionnal 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 unsigned int interp=1, const int border_condition=-1) { |
| return resize(disp.width,disp.height,depth,dim,interp,border_condition); |
| } |
| |
| //! Return an half-resized image, using a special filter. |
| /** |
| \see resize_halfXY(), resize(), get_resize(). |
| **/ |
| CImg get_resize_halfXY() const { |
| typedef typename cimg::largest<T,float>::type ftype; |
| if (is_empty()) return CImg<T>(); |
| CImg<ftype> mask = CImg<ftype>::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 unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0, |
| const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1, |
| const bool border_condition = false) const { |
| if (is_empty()) |
| throw CImgInstanceException("CImg<%s>::get_crop() : Instance image (%u,%u,%u,%u,%p) is empty.", |
| pixel_type(),width,height,depth,dim,data); |
| const unsigned int dx=x1-x0+1, dy=y1-y0+1, dz=z1-z0+1, dv=v1-v0+1; |
| CImg dest(dx,dy,dz,dv); |
| if (x0>=width || x1>=width || y0>=height || y1>=height || z0>=depth || z1>=depth || |
| v0>=dim || v1>=dim || x1<x0 || y1<y0 || z1<z0 || v1<v0) |
| switch (border_condition) { |
| case false: { cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = pix4d(x0+x,y0+y,z0+z,v0+v,0); } break; |
| default: { cimg_forXYZV(dest,x,y,z,v) dest(x,y,z,v) = pix4d(x0+x,y0+y,z0+z,v0+v); } break; |
| } else { |
| const T *psrc = ptr(x0,y0,z0,v0); |
| T *pdest = dest.ptr(0,0,0,0); |
| if (dx!=width) |
| for (unsigned int k=0; k<dv; k++) { |
| for (unsigned int z=0; z<dz; z++) { |
| for (unsigned int y=0; y<dy; y++) { |
| std::memcpy(pdest,psrc,dx*sizeof(T)); |
| pdest+=dx; |
| psrc+=width; |
| } |
| psrc+=width*(height-dy); |
| } |
| psrc+=width*height*(depth-dz); |
| } |
| else { |
| if (dy!=height) |
| for (unsigned int k=0; k<dv; k++) { |
| for (unsigned int z=0; z<dz; z++) { |
| std::memcpy(pdest,psrc,dx*dy*sizeof(T)); |
| pdest+=dx*dy; |
| psrc+=width*height; |
| } |
| psrc+=width*height*(depth-dz); |
| } |
| else { |
| if (dz!=depth) |
| for (unsigned int k=0; k<dv; k++) { |
| std::memcpy(pdest,psrc,dx*dy*dz*sizeof(T)); |
| pdest+=dx*dy*dz; |
| psrc+=width*height*depth; |
| } |
| else std::memcpy(pdest,psrc,dx*dy*dz*dv*sizeof(T)); |
| } |
| } |
| } |
| 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 unsigned int x0,const unsigned int y0,const unsigned int z0, |
| const unsigned int x1,const unsigned int y1,const unsigned 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 unsigned int x0,const unsigned int y0, |
| const unsigned int x1,const unsigned 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 unsigned int x0,const unsigned 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 unsigned int x0,const unsigned int y0,const unsigned int z0,const unsigned int v0, |
| const unsigned int x1,const unsigned int y1,const unsigned int z1,const unsigned int v1, |
| const 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 unsigned int x0,const unsigned int y0,const unsigned int z0, |
| const unsigned int x1,const unsigned int y1,const unsigned 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 unsigned int x0,const unsigned int y0, |
| const unsigned int x1,const unsigned 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 unsigned int x0,const unsigned 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(x0,0,0,0,x1,height-1,depth-1,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,y0,0,0,width-1,y1,depth-1,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,z0,0,width-1,height-1,z1,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,v0,width-1,height-1,depth-1,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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(data,width,height,depth,dim,true); |
| } |
| |
| //! Return a shared version of the instance image (const version). |
| const CImg get_shared() const { |
| return CImg<T>(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<height*depth*dim; yzv++) { |
| for (unsigned int x=0; x<width/2; x++) { const T val = *pf; *(pf++)=*pb; *(pb--)=val; } |
| pf+=width-width/2; |
| pb+=width+width/2; |
| } |
| } break; |
| case 'y': { |
| buf = new T[width]; |
| pf = ptr(); pb = ptr(0,height-1); |
| for (unsigned int zv=0; zv<depth*dim; zv++) { |
| for (unsigned int y=0; y<height/2; y++) { |
| std::memcpy(buf,pf,width*sizeof(T)); |
| std::memcpy(pf,pb,width*sizeof(T)); |
| std::memcpy(pb,buf,width*sizeof(T)); |
| pf+=width; |
| pb-=width; |
| } |
| pf+=width*(height-height/2); |
| pb+=width*(height+height/2); |
| } |
| } break; |
| case 'z': { |
| buf = new T[width*height]; |
| pf = ptr(); pb = ptr(0,0,depth-1); |
| cimg_forV(*this,v) { |
| for (unsigned int z=0; z<depth/2; z++) { |
| std::memcpy(buf,pf,width*height*sizeof(T)); |
| std::memcpy(pf,pb,width*height*sizeof(T)); |
| std::memcpy(pb,buf,width*height*sizeof(T)); |
| pf+=width*height; |
| pb-=width*height; |
| } |
| pf+=width*height*(depth-depth/2); |
| pb+=width*height*(depth+depth/2); |
| } |
| } break; |
| case 'v': { |
| buf = new T[width*height*depth]; |
| pf = ptr(); pb = ptr(0,0,0,dim-1); |
| for (unsigned int v=0; v<dim/2; v++) { |
| std::memcpy(buf,pf,width*height*depth*sizeof(T)); |
| std::memcpy(pf,pb,width*height*depth*sizeof(T)); |
| std::memcpy(pb,buf,width*height*depth*sizeof(T)); |
| pf+=width*height*depth; |
| pb-=width*height*depth; |
| } |
| } break; |
| default: |
| throw CImgArgumentException("CImg<%s>::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') { |
| 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<ndeltax-1; l++) *(--ptrd) = val; |
| } |
| } else { |
| const int ndeltax = (-deltax>=(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; l<ndeltax-1; l++) *(++ptrd) = val; |
| } |
| } |
| break; |
| case 2: { |
| const int ml = cimg::mod(deltax,width), ndeltax = (ml<=(int)width/2)?ml:(ml-(int)width); |
| if (!ndeltax) return *this; |
| T* buf = new T[cimg::abs(ndeltax)]; |
| if (ndeltax>0) 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<ndeltay-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; } |
| } |
| } else { |
| const int ndeltay = (-deltay>=(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; l<ndeltay-1; l++) { std::memcpy(ptrd,ptrs,width*sizeof(T)); ptrd+=width; } |
| } |
| } |
| break; |
| case 2: { |
| const int ml = cimg::mod(deltay,height), ndeltay = (ml<=(int)height/2)?ml:(ml-(int)height); |
| if (!ndeltay) return *this; |
| T* buf = new T[width*cimg::abs(ndeltay)]; |
| if (ndeltay>0) 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<ndeltaz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; } |
| } |
| } else { |
| const int ndeltaz = (-deltaz>=(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; l<ndeltaz-1; l++) { std::memcpy(ptrd,ptrs,width*height*sizeof(T)); ptrd+=width*height; } |
| } |
| } |
| break; |
| case 2: { |
| const int ml = cimg::mod(deltaz,depth), ndeltaz = (ml<=(int)depth/2)?ml:(ml-(int)depth); |
| if (!ndeltaz) return *this; |
| T* buf = new T[width*height*cimg::abs(ndeltaz)]; |
| if (ndeltaz>0) 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<ndeltav-1; l++) { std::memcpy(ptrd,ptrs,width*height*depth*sizeof(T)); ptrd+=width*height*depth; } |
| } else { |
| const int ndeltav = (-deltav>=(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; l<ndeltav-1; l++) { std::memcpy(ptrd,data,width*height*depth*sizeof(T)); ptrd+=width*height*depth; } |
| } |
| break; |
| case 2: { |
| const int ml = cimg::mod(deltav,dim), ndeltav = (ml<=(int)dim/2)?ml:(ml-(int)dim); |
| if (!ndeltav) return *this; |
| T* buf = new T[width*height*depth*cimg::abs(ndeltav)]; |
| if (ndeltav>0) { |
| 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<T>(); |
| 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<float> 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<float> 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<float> 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<float>(); |
| if (nblevels<1) |
| throw CImgArgumentException("CImg<%s>::get_histogram() : Can't compute an histogram with %u levels", |
| pixel_type(),nblevels); |
| T vmin=val_min, vmax=val_max; |
| CImg<float> res(nblevels,1,1,1,0); |
| if (vmin==vmax && vmin==0) { const CImgStats st(*this,false); vmin = (T)st.min; vmax = (T)st.max; } |
| cimg_for(*this,ptr,T) { |
| const int pos = (int)((*ptr-vmin)*(nblevels-1)/(vmax-vmin)); |
| if (pos>=0 && pos<(int)nblevels) res[pos]++; |
| } |
| 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; } |
| CImg<float> 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<float> 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<float> 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<typename cimg::largest<T,float>::type> get_norm_pointwise(int norm_type=2) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| CImg<restype> 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<T> 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() { |
| return CImg<T>(get_norm_pointwise()).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<typename cimg::largest<T,float>::type> get_orientation_pointwise() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| return CImg<restype>(*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<T> get_split(const char axe='x', const unsigned int nb=0) const { |
| if (is_empty()) return CImgList<T>(); |
| CImgList<T> 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; l<res.size-1; l++, x+=delta) res[l] = get_crop(x,0,0,0,x+delta-1,height-1,depth-1,dim-1); |
| res[res.size-1] = get_crop(x,0,0,0,width-1,height-1,depth-1,dim-1); |
| } break; |
| case 'y': { |
| if (nb>height) |
| 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; l<res.size-1; l++, x+=delta) res[l] = get_crop(0,x,0,0,width-1,x+delta-1,depth-1,dim-1); |
| res[res.size-1] = get_crop(0,x,0,0,width-1,height-1,depth-1,dim-1); |
| } break; |
| case 'z': { |
| if (nb>depth) |
| 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; l<res.size-1; l++, x+=delta) res[l] = get_crop(0,0,x,0,width-1,height-1,x+delta-1,dim-1); |
| res[res.size-1] = get_crop(0,0,x,0,width-1,height-1,depth-1,dim-1); |
| } break; |
| case 'v': { |
| if (nb>dim) |
| 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<res.size-1; l++, x+=delta) res[l] = get_crop(0,0,0,x,width-1,height-1,depth-1,x+delta-1); |
| res[res.size-1] = get_crop(0,0,0,x,width-1,height-1,depth-1,dim-1); |
| } break; |
| default: |
| throw CImgArgumentException("CImg<%s>::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<T>& img, const char axis='x', const char align='c') const { |
| if (img.is_empty()) return *this; |
| if (is_empty()) return img; |
| CImgList<T> 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<T> 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<T>& img, const char axis='x', const char align='c') { |
| if (img.is_empty()) 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<typename cimg::largest<T,float>::type> get_gradientXY(const int scheme=0) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImgList<restype>(2); |
| CImgList<restype> 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<typename cimg::largest<T,float>::type> get_gradientXYZ(const int scheme=0) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImgList<restype>(3); |
| CImgList<restype> 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<typename cimg::largest<T,float>::type> get_structure_tensorXY(const int scheme=1) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| CImg<restype> 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 get_structure_tensorXY(scheme).swap(*this); |
| } |
| |
| //! Return the 3D structure tensor field of an image |
| CImg<typename cimg::largest<T,float>::type> get_structure_tensorXYZ(const int scheme=1) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| CImg<restype> 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 get_structure_tensorXYZ(scheme).swap(*this); |
| } |
| |
| //@} |
| //------------------------------------- |
| // |
| //! \name Meshes and Triangulations |
| //@{ |
| //------------------------------------- |
| |
| struct _marching_squares_func { |
| const CImg<T>& ref; |
| _marching_squares_func(const CImg<T>& 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<T>& ref; |
| _marching_cubes_func(const CImg<T>& 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<T>& ref; |
| _marching_squares_func_float(const CImg<T>& 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<T>& ref; |
| _marching_cubes_func_float(const CImg<T>& 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<typename tp, typename tf> |
| const CImg& marching_squares(const float isovalue,CImgList<tp>& points, CImgList<tf>& 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<typename tp, typename tf> |
| const CImg& marching_squares(const float isovalue, |
| const float resx, const float resy, |
| CImgList<tp>& points, CImgList<tf>& 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<typename tp, typename tf> |
| const CImg& marching_cubes(const float isovalue,CImgList<tp>& points, CImgList<tf>& 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<typename tp, typename tf> |
| const CImg& marching_cubes(const float isovalue, |
| const float resx, const float resy, const float resz, |
| CImgList<tp>& points, CImgList<tf>& 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<T> get_default_LUT8() { |
| static CImg<T> 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<typename t> CImg<t> get_RGBtoLUT(const CImg<t>& palette, const bool dithering=true,const bool indexing=false) const { |
| if (is_empty()) return CImg<t>(); |
| 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<t> res(width,height,depth,indexing?1:3), pal = palette.data?palette:CImg<t>::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 (y<dimy()-1) { |
| const int ny = y+1; |
| float *ptr=pline2; cimg_forX(*this,x) { *(ptr++)=(*this)(x,ny,z,0); *(ptr++)=(*this)(x,ny,z,1); *(ptr++)=(*this)(x,ny,z,2); } |
| } |
| float *ptr1=pline1, *ptr2=pline2; |
| cimg_forX(*this,x) { |
| float R = *(ptr1++), G = *(ptr1++), B = *(ptr1++); |
| R = R<0?0:(R>255?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<float>::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<min) { min=error; best_index=off; Rbest=Rp; Gbest=Gp; Bbest=Bp; } |
| } |
| } else { |
| Rbest = (t)((unsigned char)R&0xe0); Gbest = (t)((unsigned char)G&0xe0); Bbest = (t)((unsigned char)B&0xc0); |
| best_index = (unsigned char)Rbest | ((unsigned char)Gbest>>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 (x<dimx()-1) { *(ptr1++)+= dR*7/16; *(ptr1++)+= dG*7/16; *(ptr1++)+= dB*7/16; ptr1-=3; } |
| if (y<dimy()-1) { |
| *(ptr2++)+= dR*5/16; *(ptr2++)+= dG*5/16; *ptr2+= dB*5/16; ptr2-=2; |
| if (x>0) { *(--ptr2)+= dB*3/16; *(--ptr2)+= dG*3/16; *(--ptr2)+= dR*3/16; ptr2+=3; } |
| if (x<dimx()-1) { ptr2+=3; *(ptr2++)+= dR/16; *(ptr2++)+= dG/16; *ptr2+= dB/16; ptr2-=5; } |
| } |
| } |
| ptr2+=3; |
| } |
| } |
| } |
| delete[] line1; delete[] line2; |
| return res; |
| } |
| |
| //! Convert color pixels from (R,G,B) to match the default 256 colors palette. |
| /** |
| Same as get_RGBtoLUT() with the default color palette given by get_default_LUT8(). |
| **/ |
| CImg<T> get_RGBtoLUT(const bool dithering=true, const bool indexing=false) const { |
| CImg<T> 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<T>& 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<T> 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<typename t> CImg<t> get_LUTtoRGB(const CImg<t>& palette) const { |
| if (is_empty()) return CImg<t>(); |
| 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<t> res(width,height,depth,3); |
| CImg<t> 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<T> get_LUTtoRGB() const { |
| CImg<T> foo; |
| return get_LUTtoRGB(foo); |
| } |
| |
| //! In-place version of get_LUTtoRGB(). |
| CImg& LUTtoRGB(const CImg<T>& palette) { |
| return get_LUTtoRGB(palette).swap(*this); |
| } |
| |
| //! In-place version of get_LUTroRGB(). |
| CImg& LUTtoRGB() { |
| CImg<T> 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) = 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<typename cimg::largest<T,float>::type> get_RGBtoYUV() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<typename cimg::largest<T,float>::type> get_RGBtoXYZ() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*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<x1, y-coordinate is valid, col is valid. |
| CImg& draw_scanline(const int x0, const int x1, const int y, const T *const color, |
| const float opacity=1, const float brightness=1, const bool init=false) { |
| static float nopacity=0, copacity=0; |
| static unsigned int whz=0; |
| static const T* col = 0; |
| if (init) { |
| nopacity = cimg::abs(opacity); |
| copacity = 1-cimg::max(opacity,0.0f); |
| whz = width*height*depth; |
| col = color; |
| } else { |
| const int nx0 = cimg::max(x0,0), nx1 = cimg::min(x1,(int)width-1), dx = nx1-nx0; |
| T *ptrd = ptr(0,y) + nx0; |
| if (dx>=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<dimx() && y0<dimy() && z0<dimz()) { |
| const T *col=color; |
| const unsigned int whz = width*height*depth; |
| const float nopacity = cimg::abs(opacity), copacity = 1-cimg::max(opacity,0.0f); |
| T *ptrd = ptr(x0,y0,z0,0); |
| if (opacity>=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<ny1?1:-1)*(steep?1:width); |
| |
| if (opacity>=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 3D colored line in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1). |
| /** |
| \param x0 = X-coordinate of the starting point of the line. |
| \param y0 = Y-coordinate of the starting point of the line. |
| \param z0 = Z-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 z1 = Z-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 z0, const int x1, const int y1, const int z1, |
| 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; |
| 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<typename t> CImg& draw_line(const int x0,const int y0,const int x1,const int y1, |
| const CImg<t>& texture, |
| const int tx0,const int ty0,const int tx1,const int ty1, |
| const float opacity=1) { |
| if (!is_empty()) { |
| if (texture.is_empty() || texture.dim<dim) |
| throw CImgArgumentException("CImg<%s>::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<typename t> CImg& draw_image(const CImg<t>& 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.is_empty()) |
| 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<lV; v++) { |
| for (int z=0; z<lZ; z++) { |
| for (int y=0; y<lY; y++) { |
| if (opacity>=1) for (int x=0; x<lX; x++) *(ptrd++) = (T)*(ptrs++); |
| else for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; } |
| ptrd+=offX; ptrs+=soffX; |
| } |
| ptrd+=offY; ptrs+=soffY; |
| } |
| ptrd+=offZ; ptrs+=soffZ; |
| } |
| } |
| return *this; |
| } |
| |
| #ifndef cimg_use_visualcpp6 |
| 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.is_empty()) |
| 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 (this==&sprite) return draw_image(CImg<T>(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<lV; v++) { |
| for (int z=0; z<lZ; z++) { |
| if (opacity>=1) for (int y=0; y<lY; y++) { std::memcpy(ptrd,ptrs,slX); ptrd+=width; ptrs+=sprite.width; } |
| else for (int y=0; y<lY; y++) { |
| for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*(*(ptrs++)) + copacity*(*ptrd)); ptrd++; } |
| ptrd+=offX; ptrs+=soffX; |
| } |
| ptrd+=offY; ptrs+=soffY; |
| } |
| ptrd+=offZ; ptrs+=soffZ; |
| } |
| } |
| return *this; |
| } |
| #endif |
| |
| //! Draw a masked sprite image in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0). |
| /** |
| \param sprite = sprite image. |
| \param mask = mask 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 mask_valmax = Maximum pixel value of the mask image \c mask. |
| \param opacity = opacity of the drawing. |
| \note Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite. |
| \note Clipping is supported. |
| \note Dimensions along x,y and z of \c sprite and \c mask must be the same. |
| **/ |
| template<typename ti,typename tm> CImg& draw_image(const CImg<ti>& sprite, const CImg<tm>& 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.is_empty()) |
| 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.is_empty()) |
| 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<T>(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<lV; v++) { |
| ptrm = mask.data + (ptrm - mask.data)%ssize; |
| for (int z=0; z<lZ; z++) { |
| for (int y=0; y<lY; y++) { |
| for (int x=0; x<lX; x++) { |
| const float mopacity = *(ptrm++)*opacity, |
| nopacity = cimg::abs(mopacity), copacity = mask_valmax-cimg::max(mopacity,0.0f); |
| *ptrd = (T)((nopacity*(*(ptrs++))+copacity*(*ptrd))/mask_valmax); |
| ptrd++; |
| } |
| ptrd+=offX; ptrs+=soffX; ptrm+=soffX; |
| } |
| ptrd+=offY; ptrs+=soffY; ptrm+=soffY; |
| } |
| ptrd+=offZ; ptrs+=soffZ; ptrm+=soffZ; |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a 4D filled rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0,\c v0)-(\c x1,\c y1,\c z1,\c v1). |
| /** |
| \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 z0 = Z-coordinate of the upper-left rectangle corner in the instance image. |
| \param v0 = V-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 z1 = Z-coordinate of the lower-right rectangle corner in the instance image. |
| \param v1 = V-coordinate of the lower-right rectangle corner in the instance image. |
| \param val = scalar value used to fill the rectangle area. |
| \param opacity = opacity of the drawing. |
| \note Clipping is supported. |
| **/ |
| CImg& draw_rectangle(const int x0,const int y0,const int z0,const int v0, |
| const int x1,const int y1,const int z1,const int v1, |
| const T& val,const float opacity=1.0f) { |
| if (!is_empty()) { |
| const bool bx=(x0<x1), by=(y0<y1), bz=(z0<z1), bv=(v0<v1); |
| const int nx0=bx?x0:x1, nx1=bx?x1:x0, ny0=by?y0:y1, ny1=by?y1:y0, nz0=bz?z0:z1, nz1=bz?z1:z0, nv0=bv?v0:v1, nv1=bv?v1:v0; |
| const int |
| lX = (1+nx1-nx0) + (nx1>=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<lV; v++) { |
| for (int z=0; z<lZ; z++) { |
| for (int y=0; y<lY; y++) { |
| if (opacity>=1) { |
| if (sizeof(T)!=1) { for (int x=0; x<lX; x++) *(ptrd++) = val; ptrd+=offX; } |
| else { std::memset(ptrd,(int)val,lX); ptrd+=width; } |
| } else { for (int x=0; x<lX; x++) { *ptrd = (T)(nopacity*val+copacity*(*ptrd)); ptrd++; } ptrd+=offX; } |
| } |
| ptrd+=offY; |
| } |
| ptrd+=offZ; |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a 3D filled colored rectangle in the instance image, at coordinates (\c x0,\c y0,\c z0)-(\c x1,\c y1,\c z1). |
| /** |
| \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 z0 = Z-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 z1 = Z-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 z0, |
| const int x1,const int y1,const int z1, |
| const T *const color,const float opacity=1) { |
| if (!color) throw CImgArgumentException("CImg<%s>::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 = (p1<p2)?p1:p2, pright = (p1<p2)?p2:p1; |
| if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; } |
| const int ya = ny1>dimy()?height:ny1; |
| for (int y=ny0<0?0:ny0; y<ya; y++) { |
| draw_scanline((int)xleft,(int)xright,y,color,opacity,brightness); |
| xleft+=pleft; xright+=pright; |
| } |
| if (p1<p2) { xleft=(float)nx1; pleft=p3; if (ny1<0) xleft-=ny1*pleft; } |
| else { xright=(float)nx1; pright=p3; if (ny1<0) xright-=ny1*pright; } |
| const int yb = ny2>=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<p2) { pleft=p1; pright=p2; cpleft=cp1; cpright=cp2; } |
| else { pleft=p2; pright=p1; cpleft=cp2; cpright=cp1; } |
| if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; cleft-=ny0*cpleft; cright-=ny0*cpright; } |
| const int ya = ny1<dimy()?ny1:height; |
| for (int y=(ny0<0?0:ny0); y<ya; y++) { |
| 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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,y,0,0); |
| if (opacity>=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<p2) { |
| xleft=(float)nx1; pleft=p3; cleft=nc1; cpleft=cp3; |
| if (ny1<0) { xleft-=ny1*pleft; cleft-=ny1*cpleft; } |
| } else { |
| xright=(float)nx1; pright=p3; cright=nc1; cpright=cp3; |
| if (ny1<0) { xright-=ny1*pright; cright-=ny1*cpright; } |
| } |
| const int yb = ny2>=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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,yy,0,0); |
| if (opacity>=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<typename t> 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<t>& 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.is_empty()) |
| 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<p2) { pleft=p1; pright=p2; lpxleft=lpx1; lpyleft=lpy1; lpxright=lpx2; lpyright=lpy2; } |
| else { pleft=p2; pright=p1; lpxleft=lpx2; lpyleft=lpy2; lpxright=lpx1; lpyright=lpy1; } |
| if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; lxleft-=ny0*lpxleft; lyleft-=ny0*lpyleft; |
| lxright-=ny0*lpxright; lyright-=ny0*lpyright; } |
| const int ya = ny1<dimy()?ny1:height; |
| for (int y=(ny0<0?0:ny0); y<ya; y++) { |
| 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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,y,0,0); |
| if (opacity>=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<p2) { |
| xleft=(float)nx1; pleft=p3; lxleft=(float)nlx1; lyleft=(float)nly1; lpxleft=lpx3; lpyleft=lpy3; |
| if (ny1<0) { xleft-=ny1*pleft; lxleft-=ny1*lpxleft; lyleft-=ny1*lpyleft; } |
| } else { |
| xright=(float)nx1; pright=p3; lxright=(float)nlx1; lyright=(float)nly1; lpxright=lpx3; lpyright=lpy3; |
| if (ny1<0) { xright-=ny1*pright; lxright-=ny1*lpxright; lyright-=ny1*lpyright; } |
| } |
| const int yb = ny2>=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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,yy,0,0); |
| if (opacity>=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<typename t> CImg& draw_triangle(const int x0,const int y0, |
| const int x1,const int y1, |
| const int x2,const int y2, |
| const CImg<t>& 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.is_empty()) |
| 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<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; } |
| else { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; } |
| if (ny0<0) { xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft; |
| txright-=ny0*tpxright; tyright-=ny0*tpyright; } |
| const int ya = ny1<dimy()?ny1:height; |
| for (int y=(ny0<0?0:ny0); y<ya; y++) { |
| 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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,y,0,0); |
| if (opacity>=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<p2) { |
| xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3; |
| if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; } |
| } else { |
| xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3; |
| if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; } |
| } |
| const int yb = ny2>=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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,yy,0,0); |
| if (opacity>=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<typename t> CImg& draw_triangle(const int x0,const int y0, |
| const int x1,const int y1, |
| const int x2,const int y2, |
| const CImg<t>& 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.is_empty()) |
| 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<p2) { pleft=p1; pright=p2; tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; cpleft=cp1; cpright=cp2; } |
| else { pleft=p2; pright=p1; tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; cpleft=cp2, cpright=cp1; } |
| if (ny0<0) { |
| xleft-=ny0*pleft; xright-=ny0*pright; txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft; cleft-=ny0*cpleft; |
| txright-=ny0*tpxright; tyright-=ny0*tpyright; cright-=ny0*cpright; |
| } |
| const int ya = ny1<dimy()?ny1:height; |
| for (int y=(ny0<0?0:ny0); y<ya; y++) { |
| 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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,y,0,0); |
| if (opacity>=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<p2) { |
| xleft=(float)nx1; pleft=p3; txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3; cleft=nc1; cpleft=cp3; |
| if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; cleft-=ny1*cpleft; } |
| } else { |
| xright=(float)nx1; pright=p3; txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3; cright=nc1; cpright=cp3; |
| if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; cright-=ny1*cpright; } |
| } |
| const int yb = ny2>=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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,yy,0,0); |
| if (opacity>=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<typename t, typename tl> CImg& draw_triangle(const int x0,const int y0, |
| const int x1,const int y1, |
| const int x2,const int y2, |
| const CImg<t>& texture, |
| const int tx0,const int ty0, |
| const int tx1,const int ty1, |
| const int tx2,const int ty2, |
| const CImg<tl>& light, |
| const int lx0,const int ly0, |
| const int lx1,const int ly1, |
| const int lx2,const int ly2, |
| const float opacity=1.0f) { |
| if (!is_empty()) { |
| if (texture.is_empty()) |
| 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.is_empty()) |
| 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<p2) { |
| pleft=p1; pright=p2; |
| tpxleft=tpx1; tpyleft=tpy1; tpxright=tpx2; tpyright=tpy2; |
| lpxleft=lpx1; lpyleft=lpy1; lpxright=lpx2; lpyright=lpy2; |
| } else { |
| pleft=p2; pright=p1; |
| tpxleft=tpx2; tpyleft=tpy2; tpxright=tpx1; tpyright=tpy1; |
| lpxleft=tpx2; lpyleft=tpy2; lpxright=tpx1; lpyright=tpy1; |
| } |
| if (ny0<0) { |
| xleft-=ny0*pleft; xright-=ny0*pright; |
| txleft-=ny0*tpxleft; tyleft-=ny0*tpyleft; txright-=ny0*tpxright; tyright-=ny0*tpyright; |
| lxleft-=ny0*lpxleft; lyleft-=ny0*lpyleft; lxright-=ny0*lpxright; lyright-=ny0*lpyright; |
| } |
| const int ya = ny1<dimy()?ny1:height; |
| for (int y=(ny0<0?0:ny0); y<ya; y++) { |
| 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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,y,0,0); |
| if (opacity>=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<p2) { |
| xleft=(float)nx1; pleft=p3; |
| txleft=(float)ntx1; tyleft=(float)nty1; tpxleft=tpx3; tpyleft=tpy3; |
| lxleft=(float)nlx1; lyleft=(float)nly1; lpxleft=lpx3; lpyleft=lpy3; |
| if (ny1<0) { xleft-=ny1*pleft; txleft-=ny1*tpxleft; tyleft-=ny1*tpyleft; lxleft-=ny1*lpxleft; lyleft-=ny1*lpyleft; } |
| } else { |
| xright=(float)nx1; pright=p3; |
| txright=(float)ntx1; tyright=(float)nty1; tpxright=tpx3; tpyright=tpy3; |
| lxright=(float)nlx1; lyright=(float)nly1; lpxright=lpx3; lpyright=lpy3; |
| if (ny1<0) { xright-=ny1*pright; txright-=ny1*tpxright; tyright-=ny1*tpyright; lxright-=ny1*lpxright; lyright-=ny1*lpyright; } |
| } |
| const int yb = ny2>=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<dimx())?(int)xright:(width-1); |
| if (xmin<=xmax) { |
| const int offx=whz-xmax+xmin-1; |
| T* ptrd = ptr(xmin,yy,0,0); |
| if (opacity>=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; y<ymax; y++) { |
| const float |
| Y = (float)(y-y0)+0.25f, |
| delta = b*b*Y*Y-a*(c*Y*Y-rmax*rmax), |
| sdelta = (float)((delta>0?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<oxmin) draw_scanline(xmin,oxmin-1,y,color,opacity); |
| else draw_scanline(oxmin+(oxmin==xmin?0:1),xmin,y,color,opacity); |
| if (xmax<oxmax) draw_scanline(xmax,oxmax-1,y,color,opacity); |
| else draw_scanline(oxmax+(oxmax==xmax?0:1),xmax,y,color,opacity); |
| } |
| } |
| } |
| oxmin = xmin; oxmax = xmax; |
| if (pattern) hatch=(hatch<<1)+(hatch>>(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<typename t> CImg& draw_ellipse(const int x0,const int y0,const CImg<t> &tensor, |
| const T *color,const unsigned int pattern=0L,const float opacity=1) { |
| CImgList<t> eig = tensor.get_symmetric_eigen(); |
| const CImg<t> &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<typename t> CImg& draw_text(const char *const text, |
| const int x0,const int y0, |
| const T *const fgcolor,const T *const bgcolor, |
| const CImgList<t>& font,const float opacity=1) { |
| if (!text) |
| throw CImgArgumentException("CImg<%s>::draw_text() : Specified input string is (null).",pixel_type()); |
| if (font.is_empty()) |
| 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; i<cimg::strlen(text); i++) { |
| const unsigned char c = text[i]; |
| switch (c) { |
| case '\n': y+=font[' '].height; if (x>w) w=x; x=0; break; |
| case '\t': x+=4*font[' '].width; break; |
| default: if (c<font.size) x+=font[c].width; |
| } |
| } |
| if (x!=0) { |
| if (x>w) 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<T> letter; |
| for (int i=0; i<cimg::strlen(text); i++) { |
| const unsigned char c = text[i]; |
| switch (c) { |
| case '\n': y+=font[' '].height; x=x0; break; |
| case '\t': x+=4*font[' '].width; break; |
| default: if (c<font.size) { |
| letter = font[c]; |
| const CImg& mask = (c+256)<(int)font.size?font[c+256]:font[c]; |
| if (fgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) |
| if (mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = (T)(letter(p,0,0,k)*fgcolor[k]); |
| if (bgcolor) for (unsigned int p=0; p<letter.width*letter.height; p++) |
| if (!mask(p)) cimg_forV(*this,k) letter(p,0,0,k) = bgcolor[k]; |
| if (!bgcolor && font.size>=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<T>::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<typename t> CImg& draw_text(const int x0,const int y0, |
| const T *const fgcolor,const T *const bgcolor, |
| const CImgList<t>& 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<typename t> |
| CImg& draw_quiver(const CImg<t>& 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.is_empty() || 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); |
| 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<height; y+=sampling) |
| for (unsigned int x=sampling/2; x<width; x+=sampling) { |
| const unsigned int X = x*flow.width/width, Y = y*flow.height/height; |
| float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax; |
| if (!quiver_type) { |
| const int xx = x+(int)u, yy = y+(int)v; |
| draw_arrow(x,y,xx,yy,color,45.0f,sampling/5.0f,~0L,opacity); |
| } else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color,~0L,opacity); |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a vector field in the instance image, using a colormap. |
| /** |
| \param flow = a 2d image of 2d vectors used as input data. |
| \param color = a 2d image of dimv()-D vectors corresponding to the color of each arrow. |
| \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<typename t1,typename t2> |
| CImg& draw_quiver(const CImg<t1>& flow, const CImg<t2>& color, |
| const unsigned int sampling=25, const float factor=-20, |
| const int quiver_type=0, const float opacity=1) { |
| if (!is_empty()) { |
| if (flow.is_empty() || 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.is_empty() || 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<height; y+=sampling) |
| for (unsigned int x=sampling/2; x<width; x+=sampling) { |
| const unsigned int X = x*flow.width/width, Y = y*flow.height/height; |
| float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax; |
| if (!quiver_type) { |
| const int xx = x+(int)u, yy = y+(int)v; |
| draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y).data,45.0f,sampling/5.0f,~0L,opacity); |
| } else draw_line((int)(x-0.5*u),(int)(y-0.5*v),(int)(x+0.5*u),(int)(y+0.5*v),color.get_vector_at(X,Y).data,~0L,opacity); |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a 1D graph on the instance image. |
| /** |
| \param data = an image containing the graph values I = f(x). |
| \param color = an array of dimv() values of type \c T, defining the drawing color. |
| \param gtype = define the type of the plot : |
| - 0 = Plot using linear interpolation (segments). |
| - 1 = Plot with bars. |
| - 2 = Plot using cubic interpolation (3-polynomials). |
| \param ymin = lower bound of the y-range. |
| \param ymax = upper bound of the y-range. |
| \param opacity = opacity of the drawing. |
| \note |
| - if \c ymin==ymax==0, the y-range is computed automatically from the input sample. |
| \see draw_axis(). |
| **/ |
| template<typename t> |
| CImg& draw_graph(const CImg<t>& 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<t> 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 labelled 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<typename t> CImg& draw_axis(const CImg<t>& xvalues, const int y, const T *const color, |
| const int precision=-1, 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]<xvalues[siz]) draw_arrow(0,y,width-1,y,color,30,5,~0L,opacity); |
| else draw_arrow(width-1,y,0,y,color,30,5,~0L,opacity); |
| const int yt = (y+14)<dimy()?(y+3):(y-14); |
| char txt[32]; |
| cimg_foroff(xvalues,x) { |
| if (precision>=0) std::sprintf(txt,"%.*g",precision,(double)xvalues(x)); |
| else std::sprintf(txt,"%g",(double)xvalues(x)); |
| const int xi=(int)(x*(width-1)/siz), xt = xi-(int)std::strlen(txt)*3; |
| draw_point(xi,y-1,color,opacity).draw_point(xi,y+1,color,opacity). |
| draw_text(txt,xt<0?0:xt,yt,color,0,11,opacity); |
| } |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a labelled vertical axis on the instance image. |
| template<typename t> CImg& draw_axis(const int x, const CImg<t>& yvalues, const T *const color, |
| const int precision=-1, 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]<yvalues[siz]) draw_arrow(x,0,x,height-1,color,30,5,~0L,opacity); |
| else draw_arrow(x,height-1,x,0,color,30,5,~0L,opacity); |
| char txt[32]; |
| cimg_foroff(yvalues,y) { |
| if (precision>=0) std::sprintf(txt,"%.*g",precision,(double)yvalues(y)); |
| else std::sprintf(txt,"%g",(double)yvalues(y)); |
| const int |
| yi = (int)(y*(height-1)/siz), |
| tmp = yi-5, |
| nyi = tmp<0?0:(tmp>=(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 labelled horizontal+vertical axis on the instance image. |
| template<typename tx, typename ty> CImg& draw_axis(const CImg<tx>& xvalues, const CImg<ty>& yvalues, const T *const color, |
| const int precisionx=-1, const int precisiony=-1, |
| const float opacity=1.0f) { |
| if (!is_empty()) { |
| const CImg<tx> 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<width; x++) { |
| const float nx = (float)nxvalues.linear_pix1d((float)x*sizx/wm1); |
| if (nx*ox<=0) { draw_axis(nx==0?x:x-1,yvalues,color,precisiony,opacity); break; } |
| ox = nx; |
| } |
| } |
| const CImg<ty> 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<height; y++) { |
| const float ny = (float)nyvalues.linear_pix1d((float)y*sizy/hm1); |
| if (ny*oy<=0) { draw_axis(xvalues,ny==0?y:y-1,color,precisionx,opacity); break; } |
| oy = ny; |
| } |
| } |
| } |
| return *this; |
| } |
| |
| //! Draw a labelled horizontal+vertical axis on the instance image. |
| template<typename tx, typename ty> CImg& draw_axis(const tx& x0, const tx& x1, const ty& y0, const ty& y1, |
| const T *const color, |
| const int subdivisionx=-60, const int subdivisiony=-60, |
| const int precisionx=-1, const int precisiony=-1, |
| const float opacity=1.0f) { |
| return draw_axis(CImg<tx>::sequence(subdivisionx>0?subdivisionx:1-(int)width/subdivisionx,x0,x1), |
| CImg<ty>::sequence(subdivisiony>0?subdivisiony:1-(int)height/subdivisiony,y0,y1), |
| color,precisionx,precisiony,opacity); |
| } |
| |
| //! Draw grid on the instance image |
| template<typename tx, typename ty> |
| CImg& draw_grid(const CImg<tx>& xvalues, const CImg<ty>& 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.is_empty()) 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.is_empty()) 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<unsigned int> seqx, seqy; |
| |
| if (deltax!=0) { |
| const float dx = deltax>0?deltax:width*-deltax/100; |
| const unsigned int nx = (unsigned int)(width/dx); |
| seqx = CImg<unsigned int>::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<unsigned int>::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<typename T1,typename T2> struct _draw_fill { |
| const T1 *const color; |
| const float sigma,opacity; |
| const CImg<T1> value; |
| CImg<T2> region; |
| |
| _draw_fill(const CImg<T1>& 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<T2>(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<T1>& A,const CImg<T1>& 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<T1>& 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<img.dimx() && comp(value,img.get_vector_at(xmax,y,z)); xmax++) { |
| if (opacity>=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<typename t> CImg& draw_fill(const int x,const int y,const int z, |
| const T *const color, CImg<t>& region,const float sigma=0, |
| const float opacity=1) { |
| _draw_fill<T,t> 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<bool> 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<bool> 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<nx0) cimg::swap(nx0,nx1); |
| if (ny1<ny0) cimg::swap(ny0,ny1); |
| if (nx0<0) nx0=0; |
| 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<T>::min() || val>(float)cimg::type<T>::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<T>::min() || val>(float)cimg::type<T>::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<typename t> CImg& draw_gaussian(const float xc,const float yc,const CImg<t>& 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<t> 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<float>::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<typename t> CImg& draw_gaussian(const float xc,const float yc,const float zc,const CImg<t>& 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<t> 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<float>::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 ambiant_light = Brightness (between 0..1) of the ambiant light |
| **/ |
| template<typename tp, typename tf, typename to> |
| CImg& draw_object3d(const float X, const float Y, const float Z, |
| const CImg<tp>& points, const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImgList<to>& opacities, |
| const unsigned int render_type=4, |
| const bool double_sided=false, const float focale=500, |
| const float lightx=0, const float lighty=0, const float lightz=-5000, |
| const float ambiant_light = 0.05f) { |
| |
| static CImg<float> light_texture; |
| if (is_empty() || points.is_empty() || primitives.is_empty()) return *this; |
| if (colors.is_empty() || opacities.is_empty()) |
| 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,ambiant_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, oambiant_light=0; |
| if (light_texture.is_empty() || lightx!=olightx || lighty!=olighty || lightz!=olightz || ambiant_light!=oambiant_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)+=ambiant_light).cut(0.0f,1.0f); |
| olightx = lightx; olighty = lighty; olightz = lightz; oambiant_light = ambiant_light; |
| } |
| } |
| } |
| |
| // Compute 3D to 2D projection |
| CImg<float> 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<unsigned int> visibles(primitives.size); |
| CImg<float> zrange(primitives.size); |
| unsigned int nb_visibles = 0; |
| const float zmin = -focale+1.5f; |
| { cimglist_for(primitives,l) { |
| const CImg<tf>& 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<width && y0>=0 && y0<height) { |
| visibles(nb_visibles) = (unsigned int)l; |
| zrange(nb_visibles++) = z0; |
| } |
| } break; |
| case 2: // Line or textured line |
| case 6: { |
| const unsigned int |
| i0 = (unsigned int)primitive(0), |
| i1 = (unsigned int)primitive(1); |
| const float |
| x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)), |
| x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)); |
| float xm, xM, ym, yM; |
| if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } |
| if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } |
| if (z0>zmin && z1>zmin && xM>=0 && xm<width && yM>=0 && ym<height) { |
| visibles(nb_visibles) = (unsigned int)l; |
| zrange(nb_visibles++) = 0.5f*(z0+z1); |
| } |
| } break; |
| case 3: // Triangle or textured triangle |
| case 9: { |
| const unsigned int |
| i0 = (unsigned int)primitive(0), |
| i1 = (unsigned int)primitive(1), |
| i2 = (unsigned int)primitive(2); |
| const float |
| x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)), |
| x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)), |
| x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)); |
| float xm, xM, ym, yM; |
| if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } |
| if (x2<xm) xm = x2; |
| if (x2>xM) xM = x2; |
| if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } |
| if (y2<ym) ym = y2; |
| if (y2>yM) yM = y2; |
| if (z0>zmin && z1>zmin && z2>zmin && xM>=0 && xm<width && yM>=0 && ym<height) { |
| if (double_sided || (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0)<0) { |
| visibles(nb_visibles) = (unsigned int)l; |
| zrange(nb_visibles++) = (z0+z1+z2)/3; |
| } |
| } |
| } break; |
| case 4: // Rectangle or textured rectangle |
| case 12: { |
| const unsigned int |
| i0 = (unsigned int)primitive(0), |
| i1 = (unsigned int)primitive(1), |
| i2 = (unsigned int)primitive(2), |
| i3 = (unsigned int)primitive(3); |
| const float |
| x0 = projections(i0,0), y0 = projections(i0,1), z0 = (float)(Z+points(i0,2)), |
| x1 = projections(i1,0), y1 = projections(i1,1), z1 = (float)(Z+points(i1,2)), |
| x2 = projections(i2,0), y2 = projections(i2,1), z2 = (float)(Z+points(i2,2)), |
| x3 = projections(i3,0), y3 = projections(i3,1), z3 = (float)(Z+points(i3,2)); |
| float xm, xM, ym, yM; |
| if (x0<x1) { xm = x0; xM = x1; } else { xm = x1; xM = x0; } |
| if (x2<xm) xm = x2; |
| if (x2>xM) xM = x2; |
| if (x3<xm) xm = x3; |
| if (x3>xM) xM = x3; |
| if (y0<y1) { ym = y0; yM = y1; } else { ym = y1; yM = y0; } |
| if (y2<ym) ym = y2; |
| if (y2>yM) yM = y2; |
| if (y3<ym) ym = y3; |
| if (y3>yM) yM = y3; |
| if (z0>zmin && z1>zmin && z2>zmin && z3>zmin && xM>=0 && xm<width && yM>=0 && ym<height) { |
| if (double_sided || (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0)<0) { |
| visibles(nb_visibles) = (unsigned int)l; |
| zrange(nb_visibles++) = (z0+z1+z2+z3)/4; |
| } |
| } |
| } break; |
| default: |
| throw CImgArgumentException("CImg<%s>::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<unsigned int> permutations; |
| CImg<float>(zrange.data,nb_visibles,1,1,1,true).sort(permutations,false); |
| |
| // Compute light properties |
| CImg<float> lightprops; |
| switch (render_type) { |
| case 3: { // Flat Shading |
| lightprops.assign(nb_visibles); |
| cimg_forX(lightprops,l) { |
| const CImg<tf>& 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 = (-lx*nx-ly*ny-lz*nz)/(norm*nl), |
| nfactor = double_sided?cimg::abs(factor):cimg::max(factor,0.0f); |
| lightprops[l] = cimg::min(nfactor+ambiant_light,1.0f); |
| } else lightprops[l] = 1.0f; |
| } |
| } break; |
| |
| case 4: // Gouraud Shading |
| case 5: { // Phong-Shading |
| CImg<float> points_normals(points.width,3,1,1,0); |
| cimglist_for(primitives,l) { |
| const CImg<tf>& primitive = primitives[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, |
| 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), |
| nnx = nx/norm, |
| nny = ny/norm, |
| nnz = nz/norm; |
| points_normals(i0,0)+=nnx; points_normals(i0,1)+=nny; points_normals(i0,2)+=nnz; |
| points_normals(i1,0)+=nnx; points_normals(i1,1)+=nny; points_normals(i1,2)+=nnz; |
| points_normals(i2,0)+=nnx; points_normals(i2,1)+=nny; points_normals(i2,2)+=nnz; |
| if (rectangle_flag) { |
| points_normals(i3,0)+=nnx; points_normals(i3,1)+=nny; points_normals(i3,2)+=nnz; |
| } |
| } |
| } |
| |
| 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 = double_sided?cimg::abs(factor):cimg::max(factor,0.0f); |
| lightprops[ll] = cimg::min(nfactor+ambiant_light,1.0f); |
| } |
| } else { |
| 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) = (light_texture.width/2-1)*(1+nnx); |
| lightprops(ll,1) = (light_texture.height/2-1)*(1+nny); |
| } |
| } |
| } break; |
| } |
| |
| // Draw visible primitives |
| const unsigned int opacsize = opacities.size; |
| { for (unsigned int l=0; l<nb_visibles; l++) { |
| const unsigned int n_primitive = visibles(permutations(l)); |
| const CImg<tf>& primitive = primitives[n_primitive]; |
| const CImg<T>& color = colors[n_primitive%colors.size]; |
| const CImg<to>& 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<T> 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<typename tp, typename tf, typename to> |
| CImg& draw_object3d(const float X, const float Y, const float Z, |
| const CImgList<tp>& points, const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImgList<to>& opacities, |
| const unsigned int render_type=4, |
| const bool double_sided=false, const float focale=500, |
| const float lightx=0, const float lighty=0, const float lightz=-5000, |
| const float ambiant_light = 0.05f) { |
| if (points.is_empty()) return *this; |
| CImg<tp> 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<tp>& 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,ambiant_light); |
| } |
| |
| //! Draw a 3D object in the instance image |
| template<typename tp, typename tf, typename to> |
| CImg& draw_object3d(const float X, const float Y, const float Z, |
| const CImg<tp>& points, const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImg<to>& opacities, |
| const unsigned int render_type=4, |
| const bool double_sided=false, const float focale=500, |
| const float lightx=0, const float lighty=0, const float lightz=-5000, |
| const float ambiant_light = 0.05f) { |
| CImgList<to> 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,ambiant_light); |
| } |
| |
| //! Draw a 3D object in the instance image |
| template<typename tp, typename tf, typename to> |
| CImg& draw_object3d(const float X, const float Y, const float Z, |
| const CImgList<tp>& points, const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImg<to>& opacities, |
| const unsigned int render_type=4, |
| const bool double_sided=false, const float focale=500, |
| const float lightx=0, const float lighty=0, const float lightz=-5000, |
| const float ambiant_light = 0.05f) { |
| CImgList<to> nopacities(opacities.size(),1); |
| { cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); } |
| if (points.is_empty()) return *this; |
| CImg<tp> 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<tp>& 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,ambiant_light); |
| } |
| |
| //! Draw a 3D object in the instance image |
| template<typename tp, typename tf> |
| CImg& draw_object3d(const float X, const float Y, const float Z, |
| const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_light = 0.05f, const float opacity=1.0f) { |
| return draw_object3d(X,Y,Z,points,primitives,colors, |
| CImg<float>(primitives.size,1,1,1,opacity), |
| render_type,double_sided,focale,lightx,lighty,lightz, |
| ambiant_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; p<width; p++) { |
| const float x = (float)*(ptrx++), y = (float)*(ptry++), z = (float)*(ptrz++); |
| if (x<xm) xm = x; |
| if (y<ym) ym = y; |
| if (z<zm) zm = z; |
| if (x>xM) 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<T>(*this,false).resize_object3d(siz,centering); |
| } |
| |
| //@} |
| //---------------------------- |
| // |
| //! \name Image Filtering |
| //@{ |
| //---------------------------- |
| |
| //! Return the correlation of the image by a mask. |
| /** |
| The result \p res of the correlation 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_correl = enable local normalization. |
| **/ |
| template<typename t> CImg<typename cimg::largest<T,t>::type> |
| get_correlate(const CImg<t>& mask,const unsigned int cond=1,const bool weighted_correl=false) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| typedef typename cimg::largest<t,float>::type fftype; |
| typedef typename cimg::largest<T,fftype>::type ftype; |
| |
| if (is_empty()) return CImg<restype>(); |
| if (mask.is_empty() || mask.dim!=1) |
| throw CImgArgumentException("CImg<%s>::get_correlate() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", |
| pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); |
| CImg<restype> 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 = mask(0)*(*this); 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| 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+= (*this)(x+xm,y+ym,z+zm,v)*mask(cxm+xm,cym+ym,czm+zm,0); |
| dest(x,y,z,v)=(restype)val; |
| } |
| if (cond) cimg_forYZV(*this,y,z,v) |
| for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| 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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| 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 = (*this)(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; |
| } |
| if (cond) cimg_forYZV(*this,y,z,v) |
| for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| 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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || 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<typename t> CImg& correlate(const CImg<t>& 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<typename t> CImg<typename cimg::largest<T,t>::type> |
| get_convolve(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_convol=false) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| typedef typename cimg::largest<t,float>::type fftype; |
| typedef typename cimg::largest<T,fftype>::type ftype; |
| |
| if (is_empty()) return CImg<restype>(); |
| if (mask.is_empty() || mask.dim!=1) |
| throw CImgArgumentException("CImg<%s>::get_convolve() : Specified mask (%u,%u,%u,%u,%p) is not scalar.", |
| pixel_type(),mask.width,mask.height,mask.depth,mask.dim,mask.data); |
| CImg<restype> 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 = mask(0)*(*this); 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| 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+= (*this)(x-xm,y-ym,z-zm,v)*mask(cxm+xm,cym+ym,czm+zm,0); |
| dest(x,y,z,v)=(restype)val; |
| } |
| if (cond) cimg_forYZV(*this,y,z,v) |
| for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| 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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| 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 = (*this)(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; |
| } |
| if (cond) cimg_forYZV(*this,y,z,v) |
| for (int x=0; x<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| 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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || 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<typename t> CImg& convolve(const CImg<t>& 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<typename t> CImg<typename cimg::largest<T,t>::type> |
| get_erode(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_erosion=false) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| if (mask.is_empty() || mask.dim!=1) |
| throw CImgArgumentException("CImg<%s>::get_erosion() : 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<restype> 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| restype min_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype min_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype min_val = cimg::type<restype>::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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| restype min_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype min_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype min_val = cimg::type<restype>::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<typename t> CImg& erode(const CImg<t>& 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<T> mask; |
| if (mask.width!=n) mask.assign(n,n,1,1,1); |
| const CImg<T> 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<typename t> CImg<typename cimg::largest<T,t>::type> |
| get_dilate(const CImg<t>& mask, const unsigned int cond=1, const bool weighted_dilatation=false) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| if (is_empty()) return CImg<restype>(); |
| if (mask.is_empty() || mask.dim!=1) |
| throw CImgArgumentException("CImg<%s>::get_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<restype> 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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| restype max_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype max_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype max_val = cimg::type<restype>::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<dimz()-czm; z++) for (int y=cym; y<dimy()-cym; y++) for (int x=cxm; x<dimx()-cxm; x++) { |
| restype max_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype max_val = cimg::type<restype>::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<dimx(); (y<cym || y>=dimy()-cym || z<czm || z>=dimz()-czm)?x++:((x<cxm-1 || x>=dimx()-cxm)?x++:(x=dimx()-cxm))) { |
| restype max_val = cimg::type<restype>::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<typename t> CImg& dilate(const CImg<t>& 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<T> mask; |
| if (mask.width!=n) mask.assign(n,n,1,1,1); |
| const CImg<T> 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<T>::max(), min = (double)cimg::type<T>::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 (val<min) val = min; |
| *ptr = (T)val; |
| } |
| } break; |
| case 1: { // Uniform noise |
| cimg_for(*this,ptr,T) { |
| double val = *ptr+nsigma*cimg::crand(); |
| if (val>max) val = max; |
| if (val<min) val = min; |
| *ptr = (T)val; |
| } |
| } break; |
| case 2: { // Salt & Pepper noise |
| if (st.max==st.min) { st.min=0; st.max=255; } |
| cimg_for(*this,ptr,T) if (cimg::rand()*100<nsigma) *ptr=(T)(cimg::rand()<0.5?st.max:st.min); |
| } break; |
| case 3: { // Poisson Noise |
| cimg_for(*this,ptr,T) { |
| const double z = (double)*ptr; |
| if (z<=1.0e-10) *ptr=(T)0; |
| else { |
| if (z>100.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<min) val = min; |
| *ptr = (T)val; |
| } |
| } break; |
| } |
| } |
| return *this; |
| } |
| |
| //! Return a noisy image |
| /** |
| \param sigma = power of the noise. if sigma<0, it corresponds to the percentage of the maximum image value. |
| \param ntype = noise type. can be 0=gaussian, 1=uniform or 2=Salt and Pepper. |
| \return A noisy version of the instance image. |
| **/ |
| CImg get_noise(const double sigma=-20,const unsigned int ntype=0) const { |
| return (+*this).noise(sigma,ntype); |
| } |
| |
| #define cimg_deriche_apply(x0,y0,z0,k0,nb,offset,T) { \ |
| ima = ptr(x0,y0,z0,k0); \ |
| I2 = *ima; ima+=offset; I1 = *ima; ima+=offset; \ |
| Y2 = *(Y++) = sumg0*I2; Y1 = *(Y++) = g0*I1 + sumg1*I2; \ |
| for (i=2; i<(nb); i++) { I1 = *ima; ima+=offset; \ |
| Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2; \ |
| I2=I1; Y2=Y1; Y1=Y0; } \ |
| ima-=offset; I2 = *ima; Y2 = Y1 = parity*sumg1*I2; *ima = (T)(*(--Y)+Y2); \ |
| ima-=offset; I1 = *ima; *ima = (T)(*(--Y)+Y1); \ |
| for (i=(nb)-3; i>=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<typename t> |
| CImg& blur_anisotropic(const CImg<t>& 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<T,float>::type ftype; |
| if (!is_empty() && amplitude>0) { |
| if (G.is_empty() || (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<ftype> |
| 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<length && X>=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<length && X>=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<length && X>=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<length && X>=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<length && X>=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<length && X>=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<T>::min(), M = cimg::type<T>::max(); |
| cimg_for(*this,ptrd,T) { const ftype val = *(--ptrs)/N; *ptrd = val<m?m:(val>M?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<typename t> |
| CImg get_blur_anisotropic(const CImg<t>& 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<typename tm> |
| CImg& blur_anisotropic(const CImg<tm>& 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<float> blurred = CImg<float>(*this,false).blur(alpha); |
| if (geom_factor>0) blurred*=geom_factor; |
| else blurred.normalize(0,-geom_factor); |
| |
| if (threed) { // Field for 3D volumes |
| CImg<float> 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<float> 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<typename tm> |
| CImg get_blur_anisotropic(const CImg<tm>& 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 anistropic 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<T>(),amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec,interpolation,fast_approx,geom_factor); |
| } |
| |
| //! Blur an image following in an anistropic 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<typename cimg::largest<T,float>::type> get_FFT(const char axe, const bool inverse=false) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImgList<restype>(*this).FFT(axe,inverse); |
| } |
| |
| //! Return the Fast Fourier Transform on an image |
| CImgList<typename cimg::largest<T,float>::type> get_FFT(const bool inverse=false) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImgList<restype>(*this).FFT(inverse); |
| } |
| |
| //! Apply a median filter. |
| CImg get_blur_median(const unsigned int n=3) { |
| CImg<T> 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<T> 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<T> 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<T,float>::type ftype; |
| CImg<ftype> val, vec, veloc(width,height,depth,dim); |
| |
| if (threed) { |
| CImg<ftype> 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(1.0f+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<ftype> 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(1.0f+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); |
| } |
| |
| //@} |
| //----------------------------- |
| // |
| //! \name Matrix and Vectors |
| //@{ |
| //----------------------------- |
| |
| //! Return a vector with specified coefficients |
| static CImg vector(const T& a1) { |
| return CImg<T>(1,1).fill(a1); |
| } |
| |
| //! Return a vector with specified coefficients |
| static CImg vector(const T& a1,const T& a2) { |
| return CImg<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<T>(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<siz) { i2+=2*i+1; i++; } |
| if (i2==siz) width = height = i; |
| else throw CImgInstanceException("CImg<%s>::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<T> 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>::get_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<T>(); |
| 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<T> res(N,N,1,1,0); |
| cimg_forX(res,x) res(x,x)=1; |
| return res; |
| } |
| |
| CImg& identity_matrix() { |
| return get_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<T>(1,N).sequence(a0,a1); |
| return CImg<T>(); |
| } |
| |
| //! 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<T>::matrix(1-2*(yy+zz), 2*(xy+zw), 2*(xz-yw), |
| 2*(xy-zw), 1-2*(xx+zz), 2*(yz+xw), |
| 2*(xz+yw), 2*(yz-xw), 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 { |
| CImg<T> res(height,width,depth,dim); |
| cimg_forXYZV(*this,x,y,z,v) res(y,x,z,v) = (*this)(x,y,z,v); |
| return res; |
| } |
| |
| //! 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 (*this)=get_transpose(); |
| } |
| |
| //! 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 { |
| if (use_LU) { // LU-based inverse computation |
| CImg<T> 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) = col(i); |
| } |
| } else { // SVD-based inverse computation |
| CImg<T> 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<typename cimg::largest<T,float>::type> get_inverse(const bool use_LU=true) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*this,false).inverse(use_LU); |
| } |
| |
| //! Return the pseudo-inverse (Moore-Penrose) of the matrix |
| CImg<typename cimg::largest<T,float>::type> get_pseudoinverse() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| CImg<restype> At = get_transpose(), At2(At); |
| return (((At*=*this).inverse())*=At2); |
| } |
| |
| //! Replace the matrix by its pseudo-inverse |
| CImg& pseudoinverse() { |
| typedef typename cimg::largest<T,float>::type restype; |
| CImg<restype> 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<T> arr(*this); |
| unsigned long l=0,ir=size()-1; |
| for (;;) { |
| if (ir<=l+1) { |
| if (ir==l+1 && arr[ir]<arr[l]) cimg::swap(arr[l],arr[ir]); |
| return arr[k]; |
| } else { |
| const unsigned long mid = (l+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); |
| do j--; while (arr[j]>pivot); |
| if (j<i) break; |
| cimg::swap(arr[i],arr[j]); |
| } |
| arr[l+1] = arr[j]; |
| arr[j] = 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.is_empty()) |
| 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<nb; off++) res+=data[off]*img[off]; |
| return res; |
| } |
| |
| //! Return the cross product between two 3d vectors |
| CImg& cross(const CImg& img) { |
| if (width!=1 || height<3 || img.width!=1 || img.height<3) |
| throw CImgInstanceException("CImg<%s>::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<T,float>::type ftype; |
| CImg<ftype> lu(*this); |
| CImg<unsigned int> 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<typename t> const CImg& SVD(CImg<t>& U, CImg<t>& S, CImg<t>& 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()<width) S.assign(1,width); |
| if (V.width<width || V.height<height) V.assign(width,width); |
| CImg<t> 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<dimy()) { |
| for (int k=i; k<dimy(); k++) scale+= cimg::abs(U(i,k)); |
| if (scale) { |
| for (int k=i; k<dimy(); k++) { U(i,k)/=scale; s+= U(i,k)*U(i,k); } |
| f = U(i,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h=f*g-s; U(i,i)=f-g; |
| for (int j=l; j<dimx(); j++) { |
| s = 0; for (int k=i; k<dimy(); k++) s+= U(i,k)*U(j,k); |
| f = s/h; |
| { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); } |
| } |
| { for (int k=i; k<dimy(); k++) U(i,k)*= scale; } |
| } |
| } |
| S[i]=scale*g; |
| |
| g = s = scale = 0; |
| if (i<dimy() && i!=dimx()-1) { |
| for (int k=l; k<dimx(); k++) scale += cimg::abs(U(k,i)); |
| if (scale) { |
| for (int k=l; k<dimx(); k++) { U(k,i)/= scale; s+= U(k,i)*U(k,i); } |
| f = U(l,i); g = (t)((f>=0?-1:1)*std::sqrt(s)); h = f*g-s; U(l,i) = f-g; |
| { for (int k=l; k<dimx(); k++) rv1[k]=U(k,i)/h; } |
| for (int j=l; j<dimy(); j++) { |
| s=0; for (int k=l; k<dimx(); k++) s+= U(k,j)*U(k,i); |
| { for (int k=l; k<dimx(); k++) U(k,j)+= s*rv1[k]; } |
| } |
| { for (int k=l; k<dimx(); k++) U(k,i)*= scale; } |
| } |
| } |
| anorm=cimg::max((t)anorm,(cimg::abs(S[i])+cimg::abs(rv1[i]))); |
| } |
| |
| { for (int i=dimx()-1; i>=0; i--) { |
| if (i<dimx()-1) { |
| if (g) { |
| { for (int j=l; j<dimx(); j++) V(i,j) =(U(j,i)/U(l,i))/g; } |
| for (int j=l; j<dimx(); j++) { |
| s=0; for (int k=l; k<dimx(); k++) s+= U(k,i)*V(j,k); |
| { for (int k=l; k<dimx(); k++) V(j,k)+= s*V(i,k); } |
| } |
| } |
| for (int j=l; j<dimx(); j++) V(j,i)=V(i,j)=0.0; |
| } |
| V(i,i) = 1.0; g = rv1[i]; l = i; |
| } |
| } |
| |
| { for (int i=cimg::min(dimx(),dimy())-1; i>=0; i--) { |
| l = i+1; g = S[i]; |
| for (int j=l; j<dimx(); j++) U(j,i) = 0; |
| if (g) { |
| g = 1/g; |
| for (int j=l; j<dimx(); j++) { |
| s=0; for (int k=l; k<dimy(); k++) s+= U(i,k)*U(j,k); |
| f = (s/U(i,i))*g; |
| { for (int k=i; k<dimy(); k++) U(j,k)+= f*U(i,k); } |
| } |
| { for (int j=i; j<dimy(); j++) U(i,j)*= g; } |
| } else for (int j=i; j<dimy(); j++) U(i,j)=0; |
| U(i,i)++; |
| } |
| } |
| |
| for (int k=dimx()-1; k>=0; k--) { |
| for (unsigned int its=0; its<max_iter; its++) { |
| bool flag = true; |
| for (l=k; l>=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<int> permutations(width); |
| CImg<t> 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<typename t> const CImg& SVD(CImgList<t>& 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<typename cimg::largest<T,float>::type> get_SVD(const bool sorting=true) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| CImgList<restype> 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<typename t> CImg& _LU(CImg<t>& indx, bool& d) { |
| typedef typename cimg::largest<T,float>::type ftype; |
| const int N = dimx(); |
| int imax=0; |
| CImg<ftype> 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<j; i++) { |
| ftype sum=(*this)(j,i); |
| for (int k=0; k<i; k++) sum-=(*this)(k,i)*(*this)(j,k); |
| (*this)(j,i) = (T)sum; |
| } |
| ftype vmax=0; |
| { for (int i=j; i<dimx(); i++) { |
| ftype sum=(*this)(j,i); |
| for (int k=0; k<j; k++) sum-=(*this)(k,i)*(*this)(j,k); |
| (*this)(j,i) = (T)sum; |
| const ftype tmp = vv[i]*cimg::abs(sum); |
| if (tmp>=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<N) { |
| const ftype tmp = 1/(ftype)(*this)(j,j); |
| for (int i=j+1; i<N; i++) (*this)(j,i)*=tmp; |
| } |
| } |
| return *this; |
| } |
| |
| // INNER ROUTINE : Solve a linear system, using the LU decomposition |
| template<typename t> CImg& _solve(const CImg<T>& A, const CImg<t>& indx) { |
| typedef typename cimg::largest<T,float>::type ftype; |
| const int N = size(); |
| int ii=-1; |
| ftype sum; |
| for (int i=0; i<N; i++) { |
| const int ip = (int)indx[i]; |
| ftype sum = (*this)(ip); |
| (*this)(ip) = (*this)(i); |
| if (ii>=0) for (int j=ii; j<=i-1; j++) sum-=A(j,i)*(*this)(j); |
| else if (sum!=0) ii=i; |
| (*this)(i)=sum; |
| } |
| { for (int i=N-1; i>=0; i--) { |
| sum = (*this)(i); |
| for (int j=i+1; j<N; j++) sum-=A(j,i)*(*this)(j); |
| (*this)(i)=sum/A(i,i); |
| }} |
| return *this; |
| } |
| |
| //! Solve a linear system AX=B where B=*this. (in-place version) |
| CImg& solve(const CImg& A) { |
| if (width!=1 || depth!=1 || dim!=1 || height!=A.height || A.depth!=1 || A.dim!=1) |
| throw CImgArgumentException("CImg<%s>::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<T> lu(A); |
| CImg<T> 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<typename cimg::largest<T,float>::type> get_solve(const CImg& A) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImg<restype>(*this,false).solve(A); |
| } |
| |
| //! Compute the eigenvalues and eigenvectors of a matrix. |
| template<typename t> const CImg<T>& eigen(CImg<t>& val, CImg<t> &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()<width) val.assign(1,width); |
| if (vec.size()<width*width) vec.assign(width,width); |
| switch(width) { |
| case 1: { val[0]=(t)(*this)[0]; vec[0]=(t)1; } break; |
| case 2: { |
| const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a+d; |
| double f = e*e-4*(a*d-b*c); |
| cimg::warn(f<0,"CImg<%s>::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<typename cimg::largest<T,float>::type> get_eigen() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| CImgList<restype> res(2); |
| eigen(res[0],res[1]); |
| return res; |
| } |
| |
| //! Compute the eigenvalues and eigenvectors of a matrix. |
| template<typename t> const CImg<T>& eigen(CImgList<t>& 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<typename t> const CImg<T>& symmetric_eigen(CImg<t>& val, CImg<t>& 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()<width) val.assign(1,width); |
| if (vec.data && vec.size()<width*width) vec.assign(width,width); |
| if (width<3) return eigen(val,vec); |
| CImg<t> 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<int> permutations(width); // sort eigenvalues in decreasing order |
| CImg<t> 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<typename cimg::largest<T,float>::type> get_symmetric_eigen() const { |
| typedef typename cimg::largest<T,float>::type restype; |
| CImgList<restype> res(2); |
| symmetric_eigen(res[0],res[1]); |
| return res; |
| } |
| |
| //! Compute the eigenvalues and eigenvectors of a symmetric matrix. |
| template<typename t> const CImg<T>& symmetric_eigen(CImgList<t>& eig) const { |
| if (eig.size<2) eig.assign(2); |
| symmetric_eigen(eig[0],eig[1]); |
| return *this; |
| } |
| |
| template<typename t> CImg<T>& _quicksort(const int min,const int max,CImg<t>& permutations,const bool increasing) { |
| if (min<max) { |
| const int mid = (min+max)/2; |
| if (increasing) { |
| 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]); } |
| } 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) i++; |
| while ((*this)[j]>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]<pivot) j--; |
| if (i<=j) { |
| cimg::swap((*this)[i],(*this)[j]); |
| cimg::swap(permutations[i++],permutations[j--]); |
| } |
| } while (i<=j); |
| } |
| if (min<j) _quicksort(min,j,permutations,increasing); |
| if (i<max) _quicksort(i,max,permutations,increasing); |
| } |
| } |
| return *this; |
| } |
| |
| //! Sort values of a vector and get permutations. |
| template<typename t> |
| CImg<T>& sort(CImg<t>& 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<T>& sort(const bool increasing=true) { CImg<T> foo; return sort(foo,increasing); } |
| |
| //! Get a sorted version a of vector, with permutations. |
| template<typename t> CImg<T> get_sort(CImg<t>& permutations,const bool increasing=true) { |
| return (+*this).sort(permutations,increasing); |
| } |
| |
| //! Get a sorted version of a vector. |
| CImg<T> get_sort(const bool increasing=true) { |
| return (+*this).sort(increasing); |
| } |
| |
| //! Get a permutation of the pixels |
| template<typename t> CImg<T> get_permute(const CImg<t>& permutation) const { |
| if (permutation.size()!=size()) |
| throw CImgArgumentException("CImg<%s>::get_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<T> 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<typename t> CImg<T>& permute(const CImg<t>& 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<minsiz) { w=w*minsiz/dmin; w+=(w==0); h=h*minsiz/dmin; h+=(h==0); } |
| const unsigned int dmax = cimg::max(w,h), maxsiz = max_size>=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<unsigned char> 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<dimx() && mY<dimy()) { area = 1; X = mX; Y = mY; Z = phase?Z1:Z0; } |
| if (mX<dimx() && mY>=dimy()) { area = 2; X = mX; Z = mY-height; Y = phase?Y1:Y0; } |
| if (mX>=dimx() && mY<dimy()) { area = 3; Y = mY; Z = mX-width; X = phase?X1:X0; } |
| |
| key = disp.key; |
| if (key && key!=cimg::keyCTRLLEFT) { |
| if (disp.is_pressed(cimg::keyCTRLLEFT)) { |
| switch (key) { |
| case cimg::keyARROWLEFT: |
| case cimg::keyARROWDOWN: disp.wheel--; break; |
| case cimg::keyARROWRIGHT: |
| case cimg::keyARROWUP: disp.wheel++; break; |
| 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::keyF: |
| disp.resize(disp.screen_dimx(),disp.screen_dimy()).toggle_fullscreen(); |
| disp.is_resized = true; |
| break; |
| case cimg::keyS: { |
| 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); |
| if (!visu0.is_empty()) visu0.save(filename); |
| } break; |
| default: break; |
| } |
| key = disp.key = 0; |
| } |
| } else key = 0; |
| |
| if (!area) mx = my = X = Y = Z = -1; |
| else { |
| if (disp.button&1 && phase<2) { X1 = X; Y1 = Y; Z1 = Z; } |
| if (!(disp.button&1) && phase>=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.is_empty()) { |
| if (visu0.is_empty()) { |
| CImg<T> 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<T>::is_float()) { |
| if (sizeof(T)>1) visu0.assign(tmp.normalize(0,255)); |
| else visu0.assign(tmp).normalize(0,255); |
| } else { |
| if (cimg::type<T>::id()!=cimg::type<unsigned char>::id()) { |
| const float m = cimg::type<T>::min(), M = cimg::type<T>::max(); |
| visu0.assign((CImg<float>(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<X1?X0:X1)*disp.width/(width+d), |
| y0=(Y0<Y1?Y0:Y1)*disp.height/(height+d), |
| x1=((X0<X1?X1:X0)+1)*disp.width/(width+d)-1, |
| y1=((Y0<Y1?Y1:Y0)+1)*disp.height/(height+d)-1; |
| visu.draw_rectangle(x0,y0,x1,y1,fgcolor,0.2f).draw_line(x0,y0,x1,y0,fgcolor,hatch). |
| draw_line(x1,y0,x1,y1,fgcolor,hatch).draw_line(x1,y1,x0,y1,fgcolor,hatch).draw_line(x0,y1,x0,y0,fgcolor,hatch); |
| if (d) { |
| const int |
| zx0=(int)((width+(Z0<Z1?Z0:Z1))*disp.width/(width+d)), |
| zy0=(int)((height+(Z0<Z1?Z0:Z1))*disp.height/(height+d)), |
| zx1=(int)((width+(Z0<Z1?Z1:Z0)+1)*disp.width/(width+d))-1, |
| zy1=(int)((height+(Z0<Z1?Z1:Z0)+1)*disp.height/(height+d))-1; |
| visu.draw_rectangle(zx0,y0,zx1,y1,fgcolor,0.2f).draw_line(zx0,y0,zx1,y0,fgcolor,hatch). |
| draw_line(zx1,y0,zx1,y1,fgcolor,hatch).draw_line(zx1,y1,zx0,y1,fgcolor,hatch).draw_line(zx0,y1,zx0,y0,fgcolor,hatch); |
| visu.draw_rectangle(x0,zy0,x1,zy1,fgcolor,0.2f).draw_line(x0,zy0,x1,zy0,fgcolor,hatch). |
| draw_line(x1,zy0,x1,zy1,fgcolor,hatch).draw_line(x1,zy1,x0,zy1,fgcolor,hatch).draw_line(x0,zy1,x0,zy0,fgcolor,hatch); |
| } |
| } break; |
| case 3: { |
| const int |
| x0=X0*disp.width/(width+d), |
| y0=Y0*disp.height/(height+d), |
| x1=X1*disp.width/(width+d)-1, |
| y1=Y1*disp.height/(height+d)-1; |
| visu.draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f). |
| draw_ellipse(x0,y0,(float)(x1-x0),(float)(y1-y0),1.0f,0.0f,fgcolor,hatch); |
| if (d) { |
| const int |
| zx0=(int)((width+Z0)*disp.width/(width+d)), |
| zy0=(int)((height+Z0)*disp.height/(height+d)), |
| zx1=(int)((width+Z1+1)*disp.width/(width+d))-1, |
| zy1=(int)((height+Z1+1)*disp.height/(height+d))-1; |
| visu.draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,0L,0.2f). |
| draw_ellipse(zx0,y0,(float)(zx1-zx0),(float)(y1-y0),1.0f,0.0f,fgcolor,hatch). |
| draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,0L,0.2f). |
| draw_ellipse(x0,zy0,(float)(x1-x0),(float)(zy1-zy0),1.0f,0.0f,fgcolor,hatch); |
| } |
| } break; |
| } |
| |
| if (my<12) text_down = true; |
| if (my>=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; k<dim && ctext<ltext; k++) { |
| std::sprintf(ctext,"%g ",(double)(*this)(X,Y,Z,k)); |
| ctext = text + cimg::strlen(text); |
| } |
| std::sprintf(text+cimg::strlen(text),"}"); |
| } |
| } else switch (feature_type) { |
| case 1: { |
| const double dX=(double)(X0-X1), dY=(double)(Y0-Y1), dZ=(double)(Z0-Z1), norm = std::sqrt(dX*dX+dY*dY+dZ*dZ); |
| if (depth>1) 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)", |
| X0<X1?X0:X1,Y0<Y1?Y0:Y1,Z0<Z1?Z0:Z1, |
| X0<X1?X1:X0,Y0<Y1?Y1:Y0,Z0<Z1?Z1:Z0, |
| 1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1),1+cimg::abs(Z0-Z1)); |
| else std::sprintf(text,"Box (%d,%d)-(%d,%d), Size=(%d,%d)", |
| X0<X1?X0:X1,Y0<Y1?Y0:Y1,X0<X1?X1:X0,Y0<Y1?Y1:Y0,1+cimg::abs(X0-X1),1+cimg::abs(Y0-Y1)); |
| break; |
| default: |
| if (depth>1) 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 (dmin<minsiz) { w=w*minsiz/dmin; h=h*minsiz/dmin; } |
| const unsigned int dmax = cimg::max(w,h), maxsiz = 1024; |
| if (dmax>maxsiz) { 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<typename tp, typename tf, typename to> |
| const CImg& display_object3d(const CImg<tp>& points,const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImgList<to>& 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 ambiant_light=0.05f, |
| const bool display_axes=true, float *const pose_matrix=0) const { |
| |
| // Check input arguments |
| if (points.is_empty() || primitives.is_empty() || opacities.is_empty()) |
| 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<T>(disp.width,disp.height,1,colors[0].size(),0). |
| display_object3d(points,primitives,colors,opacities,disp,centering, |
| render_static,render_motion,double_sided,focale,ambiant_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,ambiant_light); |
| |
| // Init 3D objects and compute object statistics |
| CImg<float> pose, rot_mat, |
| centered_points = centering?CImg<float>(points.width,3):CImg<float>(), |
| rotated_points(points.width,3), |
| bbox_points, rotated_bbox_points, |
| axes_points, rotated_axes_points; |
| CImgList<to> bbox_opacities, axes_opacities; |
| CImgList<T> bbox_colors, axes_colors; |
| CImgList<tf> bbox_primitives, axes_primitives; |
| float dx=0, dy=0, dz=0, ratio=1; |
| const T valmax = cimg::type<T>::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,valmax); |
| 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<tf>::vector(0,1)); |
| axes_primitives.insert(CImg<tf>::vector(0,2)); |
| axes_primitives.insert(CImg<tf>::vector(0,3)); |
| } |
| |
| // Begin user interaction loop |
| CImg<T> 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,valmax); |
| 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<float>(pose_matrix,4,4,1,1,false); else pose = CImg<float>::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,ambiant_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 |
| 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<float>::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<float>::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::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.save(filename); |
| } 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<typename tp, typename tf, typename to> |
| const CImg& display_object3d(const CImgList<tp>& points,const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImgList<to>& 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 ambiant_light=0.05f, |
| const bool display_axes=true, float *const pose_matrix=0) const { |
| CImg<tp> 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<tp>& 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,ambiant_light,display_axes,pose_matrix); |
| } |
| |
| //! High-level interface for displaying a 3d object |
| template<typename tp, typename tf, typename to> |
| const CImg& display_object3d(const CImg<tp>& points, const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImg<to>& 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 ambiant_light=0.05f, |
| const bool display_axes=true, float *const pose_matrix=0) const { |
| CImgList<to> 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,ambiant_light,display_axes,pose_matrix); |
| |
| } |
| |
| //! High-level interface for displaying a 3d object |
| template<typename tp, typename tf, typename to> |
| const CImg& display_object3d(const CImgList<tp>& points,const CImgList<tf>& primitives, |
| const CImgList<T>& colors, const CImg<to>& 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 ambiant_light=0.05f, |
| const bool display_axes=true, float *const pose_matrix=0) const { |
| CImgList<to> nopacities(opacities.size(),1); |
| cimglist_for(nopacities,l) nopacities(l,0) = opacities(l); |
| if (points.is_empty()) throw CImgArgumentException("CImg<%s>::display_object3d() : Given points are empty.", |
| pixel_type()); |
| CImg<tp> 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<tp>& 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,ambiant_light,display_axes,pose_matrix); |
| } |
| |
| //! High-level interface for displaying a 3d object |
| template<typename tp, typename tf, typename to> |
| const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_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,ambiant_light,display_axes,pose_matrix); |
| } |
| |
| //! High-level interface for displaying a 3d object |
| template<typename tp, typename tf> |
| const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_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<float>::vector(opacity), |
| disp,centering,render_static,render_motion,double_sided, |
| focale,ambiant_light,display_axes,pose_matrix); |
| } |
| |
| //! High-level interface for displaying a 3d object |
| template<typename tp, typename tf> |
| const CImg& display_object3d(const tp& points, const CImgList<tf>& primitives, |
| const CImgList<T>& 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 ambiant_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<float>::vector(opacity), |
| disp,centering,render_static,render_motion,double_sided, |
| focale,ambiant_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<T> 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<T>::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)) 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>::get_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<dest.size() && err==1; off++) { |
| err = std::fscanf(nfile,"%lf%*[^0-9.eE+-]",&val); |
| *(ptr++)=(T)val; |
| } |
| cimg::warn(off<dest.size(),"CImg<%s>::get_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>::get_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>::get_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>::get_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>::get_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<unsigned char> raw(width,height,1,1); |
| cimg::fread(raw.data,width*height,nfile); |
| dest=raw; |
| } else { // 16 bits |
| CImg<unsigned short> 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<unsigned char> 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<unsigned short> 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>::get_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<T>::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<T>::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>::get_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<<bpp; } else nb_colors=0; |
| if (nb_colors) { palette = new int[nb_colors]; cimg::fread(palette,nb_colors,nfile); } |
| const int xoffset = offset-54-4*nb_colors; |
| if (xoffset>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>::get_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>::get_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>::get_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>::get_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>::get_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>::get_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>::get_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>::get_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>::get_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<height; n++) delete[] imgData[n]; |
| delete[] imgData; |
| if (!file) cimg::fclose(nfile); |
| return res; |
| #endif |
| } |
| |
| //! Load an image from a PNG file |
| static CImg get_load_png(const char *const filename) { |
| return get_load_png(0,filename); |
| } |
| |
| //! Load an image from a PNG file |
| CImg& load_png(std::FILE *const file, const char *const filename=0) { |
| return get_load_png(file,filename).swap(*this); |
| } |
| |
| //! Load an image from a PNG file |
| CImg& load_png(const char *const filename) { |
| return get_load_png(filename).swap(*this); |
| } |
| |
| //! Load an image in TIFF format |
| // Original contribution by Jerome Boulanger. |
| static CImg get_load_tiff(const char *const filename=0) { |
| #ifndef cimg_use_tiff |
| return get_load_other(filename); |
| #else |
| CImg dest; |
| TIFF *tif = TIFFOpen(filename,"r"); |
| #if cimg_debug>=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>::get_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 == 1 || 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<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,0)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 16:{ |
| unsigned short *buf; |
| buf = (unsigned short *)_TIFFmalloc(TIFFTileSize(tif)); |
| if (buf) { |
| for (unsigned int row = 0; row<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,0)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 32:{ |
| float *buf; |
| buf = (float *)_TIFFmalloc(TIFFTileSize(tif)); |
| if (buf) { |
| for (unsigned int row = 0; row<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,0)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| } |
| } |
| else { |
| switch(bitspersample){ |
| case 8:{ |
| unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif)); |
| if (buf) { |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| for (unsigned int row = 0; row<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,vv)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 16:{ |
| unsigned short *buf = (unsigned short *)_TIFFmalloc(TIFFTileSize(tif)); |
| if (buf) { |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| for (unsigned int row = 0; row<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,vv)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 32:{ |
| float *buf = (float *)_TIFFmalloc(TIFFTileSize(tif)); |
| if (buf) { |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| for (unsigned int row = 0; row<ny; row+=th) { |
| for (unsigned int col = 0; col<nx; col+=tw) { |
| if (TIFFReadTile(tif,buf,col,row,0,vv)<0) { |
| _TIFFfree(buf); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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<cimg::min( row+th,(unsigned int)ny);rr++) |
| for (unsigned int cc=col;cc<cimg::min( col+tw,(unsigned int)nx);cc++) |
| dest(cc,rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| } |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| } |
| } |
| } else { |
| if (config==PLANARCONFIG_CONTIG) { |
| switch(bitspersample){ |
| case 8 :{ |
| unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_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; rr<nrow; rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 16:{ |
| unsigned short *buf = (unsigned short *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_load_tiff() : File '%s', error while reading a strip.", |
| pixel_type(),filename?filename:"(FILE*)"); |
| } |
| unsigned short * ptr = buf; |
| for (unsigned int rr=0; rr<nrow; rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 32:{ |
| float *buf = (float *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_load_tiff() : File '%s', error while reading a strip.", |
| pixel_type(),filename?filename:"(FILE*)"); |
| } |
| float * ptr = buf; |
| for (unsigned int rr=0; rr<nrow; rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| |
| } |
| } |
| else { |
| switch(bitspersample){ |
| case 8 :{ |
| unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (unsigned int vv=0;vv<samplesperpixel;vv++){ |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_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;rr<nrow; rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| }} |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 16:{ |
| unsigned short *buf = (unsigned short *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_load_tiff() : File '%s', error while reading a strip.", |
| pixel_type(),filename?filename:"(FILE*)"); |
| } |
| unsigned short * ptr = buf; |
| for (unsigned int rr=0;rr<nrow;rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| case 32:{ |
| float *buf = (float *)_TIFFmalloc(TIFFStripSize(tif)); |
| if (buf) { |
| uint32 row, rowsperstrip = (uint32)-1; |
| TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); |
| for (unsigned int vv=0;vv<samplesperpixel;vv++) |
| for (row = 0; row<ny; row+= rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>ny?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>::get_load_tiff() : File '%s', error while reading a strip.", |
| pixel_type(),filename?filename:"(FILE*)"); |
| } |
| float * ptr = buf; |
| for (unsigned int rr=0;rr<nrow;rr++) |
| for (unsigned int cc=0;cc<nx;cc++) |
| dest(cc,row+rr,dir,vv)= (T)(float)*(ptr++); |
| } |
| _TIFFfree(buf); |
| } |
| break; |
| } |
| } |
| } |
| } |
| } |
| else { |
| uint32* raster = (uint32*)_TIFFmalloc(nx * ny * sizeof (uint32)); |
| if (!raster) { |
| _TIFFfree(raster); |
| TIFFClose(tif); |
| throw CImgException("CImg<%s>::get_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>::get_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>::get_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>::get_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>::get_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<T> 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 <chris_hormann@gmx.de> |
| 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>::get_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<T> res(sizex,sizey,sizez,sizev,0); |
| if (res.is_empty()) 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<T> 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>::get_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>::get_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>::get_load_inr() : TYPE is not fully defined",pixel_type()); |
| if(out[6]<0) throw CImgIOException("CImg<%s>::get_load_inr() : PIXSIZE is not fully defined",pixel_type()); |
| if(out[7]<0) throw CImgIOException("CImg<%s>::get_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<T> 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>::get_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>::get_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>::get_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 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; |
| char body[1024]; |
| const char *ext = cimg::filename_split(filename,body); |
| 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) return CImg<T>(); |
| std::sprintf(body+cimg::strlen(body)-3,"img"); |
| file = cimg::fopen(body,"rb"); |
| if (!file) { cimg::fclose(file_header); return CImg<T>(); } |
| } else throw CImgIOException("CImg<%s>::get_load_analyze() : Filename '%s', not recognized as an Analyze 7.5 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); |
| 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>::get_load_analyze() : Specified image has zero dimensions.",pixel_type()); |
| cimg::warn(dim[0]>4,"CImg<%s>::get_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 |
| 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,file); |
| 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,file); |
| 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,file); |
| 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,file); |
| 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,file); |
| 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(file); |
| throw CImgIOException("CImg<%s>::get_load_analyze() : File '%s, cannot read images width 'datatype = %d'", |
| pixel_type(),filename,datatype); |
| } |
| cimg::fclose(file); |
| 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<T>::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<T>::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>::get_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<T>::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>::get_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<T>::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<T> 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.is_empty()) |
| throw CImgIOException("CImg<%s>::get_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>::get_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<T>::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<typename tf,typename tc> |
| static CImg<T> get_load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& colors, |
| const bool invert_faces=false) { |
| std::FILE *file=cimg::fopen(filename,"r"); |
| unsigned int nb_points=0, nb_triangles=0; |
| int err; |
| if ((err = std::fscanf(file,"OFF%u%u%*[^\n]",&nb_points,&nb_triangles))!=2) { |
| cimg::fclose(file); |
| throw CImgIOException("CImg<%s>::get_load_off() : File '%s' is not a valid OFF file.",pixel_type(),filename); |
| } |
| |
| // Read points data |
| CImg<T> points(nb_points,3); |
| float X=0,Y=0,Z=0; |
| cimg_forX(points,l) { |
| if ((err = std::fscanf(file,"%f%f%f%*[^\n]",&X,&Y,&Z))!=3) { |
| cimg::fclose(file); |
| throw CImgIOException("CImg<%s>::get_load_off() : File '%s', cannot read point %u.\n",pixel_type(),filename,l); |
| } |
| 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) { |
| unsigned int prim=0, i0=0, i1=0, i2=0, i3=0; |
| char s_colors[256] = {'\0'}; |
| if ((err = std::fscanf(file,"%u",&prim))!=1) stopflag=true; |
| else switch (prim) { |
| case 3: { |
| if ((err = std::fscanf(file,"%u%u%u%255[^\n]",&i0,&i1,&i2,s_colors))<3) stopflag = true; |
| else { |
| float c0=0.5, c1=0.5, c2=0.5; |
| std::sscanf(s_colors,"%f%f%f",&c0,&c1,&c2); |
| if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2)); |
| else primitives.insert(CImg<tf>::vector(i0,i2,i1)); |
| colors.insert(CImg<tc>::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,s_colors))<4) stopflag = true; |
| else { |
| float c0=0.5, c1=0.5, c2=0.5; |
| std::sscanf(s_colors,"%f%f%f",&c0,&c1,&c2); |
| if (invert_faces) primitives.insert(CImg<tf>::vector(i0,i1,i2,i3)); |
| else primitives.insert(CImg<tf>::vector(i0,i3,i2,i1)); |
| colors.insert(CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255),(tc)(c2*255))); |
| } |
| } break; |
| default: stopflag = true; |
| } |
| } |
| cimg::fclose(file); |
| cimg::warn(primitives.size!=nb_triangles, |
| "CImg<%s>::get_load_off() : File '%s' contained %u triangles instead of %u as claimed in the header.", |
| pixel_type(),filename,primitives.size,nb_triangles); |
| return points; |
| } |
| |
| //! In-place version of get_load_off() |
| template<typename tf,typename tc> |
| CImg& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& 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)) 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 file. |
| const CImg& save_analyze(const char *const filename, const float *const voxsize=0) const { |
| if (is_empty()) throw CImgInstanceException("CImg<%s>::save_analyze() : 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_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"); |
| } |
| ((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); |
| 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<T> 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<T> 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<T>(*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<height; row++) imgData[row] = new png_byte[byte_depth * numChan * width]; |
| const T *pC0 = ptr(0,0,0,0); |
| switch(pixel_bit_depth_flag) { |
| case 7 : { // Gray 8-bit |
| cimg_forY(*this,y) { |
| unsigned char *ptrs = imgData[y]; |
| cimg_forX(*this,x) *(ptrs++) = (unsigned char)*(pC0++); |
| } |
| } break; |
| case 14: { // Gray w/ Alpha 8-bit |
| const T *pC1 = ptr(0,0,0,1); |
| cimg_forY(*this,y) { |
| unsigned char *ptrs = imgData[y]; |
| cimg_forX(*this,x) { |
| *(ptrs++) = (unsigned char)*(pC0++); |
| *(ptrs++) = (unsigned char)*(pC1++); |
| } |
| } |
| } break; |
| case 21: { // RGB 8-bit |
| const T *pC1 = ptr(0,0,0,1); |
| const T *pC2 = ptr(0,0,0,2); |
| cimg_forY(*this,y) { |
| unsigned char *ptrs = imgData[y]; |
| cimg_forX(*this,x) { |
| *(ptrs++) = (unsigned char)*(pC0++); |
| *(ptrs++) = (unsigned char)*(pC1++); |
| *(ptrs++) = (unsigned char)*(pC2++); |
| } |
| } |
| } break; |
| case 28: { // RGB x/ Alpha 8-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 char *ptrs = imgData[y]; |
| cimg_forX(*this,x){ |
| *(ptrs++) = (unsigned char)*(pC0++); |
| *(ptrs++) = (unsigned char)*(pC1++); |
| *(ptrs++) = (unsigned char)*(pC2++); |
| *(ptrs++) = (unsigned char)*(pC3++); |
| } |
| } |
| } break; |
| case 15: { // Gray 16-bit |
| cimg_forY(*this,y){ |
| unsigned short *ptrs = reinterpret_cast<unsigned short*>(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<unsigned short*>(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<unsigned short*>(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<unsigned short*>(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<height; n++) delete[] imgData[n]; |
| delete[] imgData; |
| if (!file) cimg::fclose(nfile); |
| return *this; |
| #endif |
| } |
| |
| //! Save a file in PNG format |
| const CImg& save_png(const char *const filename) const { |
| return save_png(0,filename); |
| } |
| |
| //! Save a file in TIFF format. |
| const CImg& save_tiff(const char *const filename) const { |
| if (is_empty()) throw CImgInstanceException("CImg<%s>::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; dir<depth; dir++) { |
| TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32)dimx()); |
| TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32)dimy()); |
| TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); |
| TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp); |
| TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp); |
| TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); |
| TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric); |
| TIFFSetField(out, TIFFTAG_COMPRESSION, compression); |
| rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip); |
| TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip); |
| TIFFSetField(out, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); |
| TIFFSetField(out, TIFFTAG_SOFTWARE, "CImg"); |
| T *buf = (T *)_TIFFmalloc(TIFFStripSize(out)); |
| if (buf){ |
| for (unsigned int row = 0; row < height; row+=rowsperstrip) { |
| uint32 nrow = (row+rowsperstrip>height?height-row:rowsperstrip); |
| tstrip_t strip = TIFFComputeStrip(out, row, 0); |
| tsize_t i = 0; |
| for (unsigned int rr=0; rr<nrow; rr++) |
| for (unsigned int cc=0;cc<width;cc++) |
| for (unsigned int vv=0;vv<spp;vv++) |
| buf[i++] = (*this)(cc,row+rr,dir,vv); |
| if(TIFFWriteEncodedStrip(out, strip, buf, i*sizeof(T))<0){ |
| throw CImgException("CImg<%s>::get_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<T>& 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<T>& 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<wh; k++) { |
| *(nbuffer++) = (unsigned char)(*(ptr1++)); |
| *(nbuffer++) = (unsigned char)(*(ptr2++)); |
| *(nbuffer++) = (unsigned char)(*(ptr3++)); |
| *(nbuffer++) = (unsigned char)(ptr4?(*(ptr4++)):255); |
| } |
| cimg::fwrite(buffer,4*wh,nfile); |
| if (!file) cimg::fclose(nfile); |
| delete[] buffer; |
| return *this; |
| } |
| |
| //! Save the image as a RGBA file |
| const CImg& save_rgba(const char *const filename) const { |
| return save_rgba(0,filename); |
| } |
| |
| //! Save the image as a RGB file |
| const CImg& save_rgb(std::FILE *const file, const char *const filename=0) const { |
| if (is_empty()) throw CImgInstanceException("CImg<%s>::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<wh; k++) { |
| *(nbuffer++) = (unsigned char)(*(ptr1++)); |
| *(nbuffer++) = (unsigned char)(*(ptr2++)); |
| *(nbuffer++) = (unsigned char)(*(ptr3++)); |
| } |
| cimg::fwrite(buffer,3*wh,nfile); |
| if (!file) cimg::fclose(nfile); |
| delete[] buffer; |
| return *this; |
| } |
| |
| //! Save the image as a RGB file |
| const CImg& save_rgb(const char *const filename) const { |
| return save_rgb(0,filename); |
| } |
| |
| //! Get a 40x38 color logo of a 'danger' item |
| static CImg get_logo40x38() { |
| static bool first_time = true; |
| static CImg<T> 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<res.width*res.height;) { |
| const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++); |
| for (unsigned int l=0; l<n; off++,l++) { *(ptr1++) = (T)r; *(ptr2++) = (T)g; *(ptr3++) = (T)b; } |
| } |
| first_time = false; |
| } |
| return res; |
| } |
| |
| //! Save OFF files (GeomView 3D object files) |
| template<typename tf, typename tc> |
| const CImg& save_off(std::FILE *const file, const char *const filename, |
| const CImgList<tf>& primitives, const CImgList<tc>& 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()); |
| 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(); |
| switch (prim) { |
| case 3: { |
| 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), |
| (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); |
| 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), |
| (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); |
| } break; |
| case 4: { |
| 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), |
| (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); |
| 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), |
| (float)(colors(l,0)/255.0f),(float)(colors(l,1)/255.0f),(float)(colors(l,2)/255.0f)); |
| } break; |
| } |
| } |
| if (!file) cimg::fclose(nfile); |
| return *this; |
| } |
| |
| //! Save OFF files (GeomView 3D object files) |
| template<typename tf, typename tc> |
| const CImg& save_off(const char *const filename, |
| const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const { |
| return save_off(filename,primitives,colors,invert_faces); |
| } |
| |
| }; |
| |
| |
| /* |
| #----------------------------------------- |
| # |
| # |
| # |
| # Definition of the CImgList<> structure |
| # |
| # |
| # |
| #------------------------------------------ |
| */ |
| |
| //! Class representing list of images CImg<T>. |
| template<typename T> 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<T> *data; |
| |
| //! Define a CImgList<T>::iterator |
| typedef CImg<T>* iterator; |
| |
| //! Define a CImgList<T>::const_iterator |
| typedef const CImg<T>* 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<typename t> CImgList(const CImgList<t>& 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<typename t> CImgList(const CImgList<t>& 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<typename t> CImgList& assign(const CImgList<t>& 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<T>[allocsize=cimg::nearest_pow2(n)]; |
| } |
| |
| //! In-place version of the previous constructor |
| CImgList& assign(const unsigned int n) { |
| if (n) { |
| if (allocsize<n || allocsize>(n<<2)) { |
| if (data) delete[] data; |
| data = new CImg<T>[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<typename t> CImgList(const unsigned int n, const CImg<t>& img, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(n,img,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t> CImgList& assign(const unsigned int n, const CImg<t>& 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<typename t> explicit CImgList(const CImg<t>& img, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t> CImgList& assign(const CImg<t>& img, const bool shared=false) { |
| return assign(1,img,shared); |
| } |
| |
| //! Construct an image list from two images |
| template<typename t1, typename t2> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2> CImgList& assign(const CImg<t1>& img1, const CImg<t2>& 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<typename t1, typename t2, typename t3> CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,img3,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2, typename t3> CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const bool shared=false) { |
| 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<typename t1, typename t2, typename t3, typename t4> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& 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<typename t1, typename t2, typename t3, typename t4> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& 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<typename t1, typename t2, typename t3, typename t4, typename t5> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,img3,img4,img5,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2, typename t3, typename t4, typename t5> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const bool shared=false) { |
| 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,img3,img4,img5,img6,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const bool shared=false) { |
| 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,img3,img4,img5,img6,img7,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const bool shared=false) { |
| 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false): |
| size(0),allocsize(0),data(0) { |
| assign(img1,img2,img3,img4,img5,img6,img7,img8,shared); |
| } |
| |
| //! In-place version of the previous constructor |
| template<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const bool shared=false) { |
| 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const CImg<t9>& 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const CImg<t9>& 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9, typename t10> |
| CImgList(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const CImg<t9>& img9, const CImg<t10>& 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<typename t1, typename t2, typename t3, typename t4, typename t5, typename t6, typename t7, typename t8, typename t9, typename t10> |
| CImgList& assign(const CImg<t1>& img1, const CImg<t2>& img2, const CImg<t3>& img3, const CImg<t4>& img4, const CImg<t5>& img5, |
| const CImg<t6>& img6, const CImg<t7>& img7, const CImg<t8>& img8, const CImg<t9>& img9, const CImg<t10>& 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<T>::id(); |
| } |
| |
| //! Return \p true if list is empty |
| bool is_empty() const { |
| return (!data || !size); |
| } |
| |
| //! Return \c true if the list contains an image with indice k |
| bool contains(const int k) const { |
| return data && k<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 |
| //@{ |
| //------------------------------ |
| |
| //! Assignement operator |
| template<typename t> CImgList& operator=(const CImgList<t>& list) { |
| return assign(list); |
| } |
| |
| CImgList& operator=(const CImgList& list) { |
| return assign(list); |
| } |
| |
| //! Assignement operator. |
| template<typename t> CImgList& operator=(const CImg<t>& img) { |
| cimglist_for(*this,l) data[l]=img; |
| return *this; |
| } |
| |
| //! Assignement operator. |
| CImgList& operator=(const T& val) { |
| cimglist_for(*this,l) data[l].fill(val); |
| return *this; |
| } |
| |
| //! Operator+ |
| CImgList operator+() const { |
| return CImgList<T>(*this); |
| } |
| |
| //! Operator+= |
| #ifdef cimg_use_visualcpp6 |
| CImgList& operator+=(const T& val) { |
| #else |
| template<typename t> CImgList& operator+=(const t& val) { |
| #endif |
| cimglist_for(*this,l) (*this)[l]+=val; |
| return *this; |
| } |
| |
| //! Operator+= |
| template<typename t> CImgList& operator+=(const CImgList<t>& list) { |
| const unsigned int sizemax = min(size,list.size); |
| for (unsigned int l=0; l<sizemax; l++) (*this)[l]+=list[l]; |
| return *this; |
| } |
| |
| //! Operator++ |
| CImgList& operator++() { |
| cimglist_for(*this,l) (*this)[l]++; |
| return *this; |
| } |
| |
| //! Operator- |
| CImgList operator-() const { |
| CImgList<T> 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<typename t> CImgList& operator-=(const t& val) { |
| #endif |
| cimglist_for(*this,l) (*this)[l]-=val; |
| return *this; |
| } |
| |
| //! Operator-=. |
| template<typename t> CImgList& operator-=(const CImgList<t>& list) { |
| const unsigned int sizemax = min(size,list.size); |
| for (unsigned int l=0; l<sizemax; l++) (*this)[l]-=list[l]; |
| return *this; |
| } |
| |
| //! Operator-- |
| CImgList& operator--() { |
| cimglist_for(*this,l) (*this)[l]--; |
| return *this; |
| } |
| |
| //! Operator*=. |
| #ifdef cimg_use_visualcpp6 |
| CImgList& operator*=(const double val) { |
| #else |
| template<typename t> CImgList& operator*=(const t& val) { |
| #endif |
| cimglist_for(*this,l) (*this)[l]*=val; |
| return *this; |
| } |
| |
| //! Operator*=. |
| template<typename t> CImgList& operator*=(const CImgList<t>& list) { |
| const unsigned int N = cimg::min(size,list.size); |
| for (unsigned int l=0; l<N; l++) (*this)[l]*=list[l]; |
| return this; |
| } |
| |
| //! Operator/=. |
| #ifdef cimg_use_visualcpp6 |
| CImgList& operator/=(const double val) { |
| #else |
| template<typename t> CImgList& operator/=(const t& val) { |
| #endif |
| cimglist_for(*this,l) (*this)[l]/=val; |
| return *this; |
| } |
| |
| //! Operator/=. |
| template<typename t> CImgList& operator/=(const CImgList<t>& list) { |
| const unsigned int N = cimg::min(size,list.size); |
| for (unsigned int l=0; l<N; l++) (*this)[l]/=list[l]; |
| return this; |
| } |
| |
| //@} |
| //------------------------- |
| // |
| //! \name List Manipulation |
| //@{ |
| //------------------------- |
| |
| //! Return a reference to the i-th element of the image list. |
| CImg<T>& 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<T>& 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<T>::operator[] |
| CImg<T>& operator()(const unsigned int pos) { return (*this)[pos]; } |
| const CImg<T>& 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<T>::operator[], with boundary checking |
| CImg<T>& 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<T>& 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<T>& back() { |
| return (*this)(size-1); |
| } |
| |
| const CImg<T>& back() const { |
| return (*this)(size-1); |
| } |
| |
| //! Returns a reference to the first element |
| CImg<T>& front() { |
| return *data; |
| } |
| |
| const CImg<T>& 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<typename t> CImgList& insert(const CImg<t>& 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<T> *new_data = (++size>allocsize)?new CImg<T>[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<T>)*pos); |
| if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos)); |
| std::memset(data,0,sizeof(CImg<T>)*(size-1)); |
| delete[] data; |
| data = new_data; |
| } |
| else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(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<T>& 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<T> *new_data = (++size>allocsize)?new CImg<T>[allocsize?(allocsize<<=1):(allocsize=1)]:0; |
| if (!size || !data) { |
| data = new_data; |
| if (shared && !img.is_empty()) { |
| 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<T>)*pos); |
| if (pos!=size-1) std::memcpy(new_data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos)); |
| std::memset(data,0,sizeof(CImg<T>)*(size-1)); |
| delete[] data; |
| data = new_data; |
| } |
| else if (pos!=size-1) memmove(data+pos+1,data+pos,sizeof(CImg<T>)*(size-1-pos)); |
| if (shared && !img.is_empty()) { |
| 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<typename t> CImgList& insert(const CImg<t>& img, const unsigned int pos) { |
| return insert(img,pos,false); |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const CImg<t>& img, const unsigned int pos, const bool shared=false) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(img,pos,shared); |
| } |
| |
| //! Insert a copy of the image \p img at the current image list. |
| template<typename t> CImgList& insert(const CImg<t>& img) { |
| return insert(img,size); |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(img); |
| } |
| |
| //! Insert a copy of the image \p img at the current image list. |
| CImgList& operator<<(const CImg<T>& img) { |
| return insert(img); |
| } |
| |
| //! Insert n copies of the image \p img into the current image list, at position \p pos. |
| template<typename t> CImgList& insert(const unsigned int n, const CImg<t>& img, const unsigned int pos) { |
| for (unsigned int i=0; i<n; i++) insert(img,pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const unsigned int n, const CImg<t>& img, const unsigned int pos) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(n,img,pos); |
| } |
| |
| |
| //! Insert n copies of the image \p img at the end of the list. |
| template<typename t> CImgList& insert(const unsigned int n, const CImg<t>& img) { |
| for (unsigned int i=0; i<n; i++) insert(img); |
| return *this; |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const unsigned int n, const CImg<t>& img) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(n,img); |
| } |
| |
| //! Insert a copy of the image list \p list into the current image list, starting from position \p pos. |
| template<typename t> CImgList& insert(const CImgList<t>& list, const unsigned int pos) { |
| cimglist_for(list,l) insert(list[l],pos+l); |
| return *this; |
| } |
| |
| CImgList& insert(const CImgList<T>& list, const unsigned int pos) { |
| if (this!=&list) cimglist_for(list,l) insert(list[l],pos+l); |
| else insert(CImgList<T>(list),pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const CImgList<t>& list, const unsigned int pos) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(list,pos); |
| } |
| |
| //! Append a copy of the image list \p list at the current image list. |
| template<typename t> CImgList& insert(const CImgList<t>& list) { |
| return insert(list,size); |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const CImgList<t>& list) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*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<typename t> CImgList& insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos) { |
| for (unsigned int i=0; i<n; i++) insert(list,pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(n,list,pos); |
| } |
| |
| //! Insert n copies of the list at the end of the current list |
| template<typename t> CImgList& insert(const unsigned int n, const CImgList<t>& list) { |
| for (unsigned int i=0; i<n; i++) insert(list); |
| return *this; |
| } |
| |
| template<typename t> CImgList<typename cimg::largest<T,t>::type> get_insert(const unsigned int n, const CImgList<t>& list) const { |
| typedef typename cimg::largest<T,t>::type restype; |
| return CImgList<restype>(*this).insert(n,list); |
| } |
| |
| //! Insert image \p img at the end of the list. |
| template<typename t> CImgList& push_back(const CImg<t>& img) { |
| return insert(img); |
| } |
| |
| //! Insert image \p img at the front of the list. |
| template<typename t> CImgList& push_front(const CImg<t>& img) { |
| return insert(img,0); |
| } |
| |
| //! Insert list \p list at the end of the current list. |
| template<typename t> CImgList& push_back(const CImgList<t>& list) { |
| return insert(list); |
| } |
| |
| //! Insert list \p list at the front of the current list. |
| template<typename t> CImgList& push_front(const CImgList<t>& list) { |
| return insert(list,0); |
| } |
| |
| //! Insert a shared copy of the image \p img into the current image list, at position \p pos. |
| template<typename t> CImgList& insert_shared(const CImg<t>& img, const unsigned int pos) { |
| return insert(img,pos,true); |
| } |
| |
| template<typename t> CImgList get_insert_shared(const CImg<t>& img, const unsigned int pos) const { |
| return CImgList<T>(*this).insert_shared(img,pos); |
| } |
| |
| //! Insert a shared copy of the image \p img at the current image list. |
| template<typename t> CImgList& insert_shared(const CImg<t>& img) { |
| return insert_shared(img,size); |
| } |
| |
| template<typename t> CImgList get_insert_shared(const CImg<t>& img) const { |
| return CImgList<T>(*this).insert_shared(img); |
| } |
| |
| //! Insert n shared copies of the image \p img into the current image list, at position \p pos. |
| template<typename t> CImgList& insert_shared(const unsigned int n, const CImg<t>& img, const unsigned int pos) { |
| for (unsigned int i=0; i<n; i++) insert_shared(img,pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList get_insert_shared(const unsigned int n, const CImg<t>& img, const unsigned int pos) const { |
| return CImgList<T>(*this).insert_shared(n,img,pos); |
| } |
| |
| //! Insert n shared copies of the image \p img at the end of the list. |
| template<typename t> CImgList& insert_shared(const unsigned int n, const CImg<t>& img) { |
| for (unsigned int i=0; i<n; i++) insert_shared(img); |
| return *this; |
| } |
| |
| template<typename t> CImgList get_insert_shared(const unsigned int n, const CImg<t>& img) const { |
| return CImgList<T>(*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<typename t> CImgList& insert_shared(const CImgList<t>& list, const unsigned int pos) { |
| if (this!=&list) cimglist_for(list,l) insert_shared(list[l],pos+l); |
| else insert_shared(CImgList<T>(list),pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList get_insert_shared(const CImgList<t>& list, const unsigned int pos) const { |
| return CImgList<T>(*this).insert_shared(list,pos); |
| } |
| |
| //! Append a shared copy of the image list \p list at the current image list. |
| template<typename t> CImgList& insert_shared(const CImgList<t>& list) { |
| return insert_shared(list,size); |
| } |
| |
| template<typename t> CImgList get_insert_shared(const CImgList<t>& list) const { |
| return CImgList<T>(*this).insert_shared(list); |
| } |
| |
| //! Insert n shared copies of the list \p list at position \p pos of the current list. |
| template<typename t> CImgList& insert_shared(const unsigned int n, const CImgList<t>& list, const unsigned int pos) { |
| for (unsigned int i=0; i<n; i++) insert_shared(list,pos); |
| return *this; |
| } |
| |
| template<typename t> CImgList get_insert_shared(const unsigned int n, const CImgList<t>& list, const unsigned int pos) const { |
| return CImgList<T>(*this).insert_shared(n,list,pos); |
| } |
| |
| //! Insert n shared copies of the list \p list at the end of the list |
| template<typename t> CImgList& insert_shared(const unsigned int n, const CImgList<t>& list) { |
| return insert_shared(n,list,size); |
| } |
| |
| template<typename t> CImgList get_insert_shared(const unsigned int n, const CImgList<t>& list) const { |
| return CImgList<T>(*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<T>)*(size-pos)); |
| CImg<T> &tmp = data[size]; |
| tmp.width = tmp.height = tmp.depth = tmp.dim = 0; tmp.data = 0; |
| } |
| } else { // Removing item with reallocation. |
| allocsize>>=2; |
| CImg<T> *new_data = new CImg<T>[allocsize]; |
| if (pos) std::memcpy(new_data,data,sizeof(CImg<T>)*pos); |
| if (pos!=size) std::memcpy(new_data+pos,data+pos+1,sizeof(CImg<T>)*(size-pos)); |
| std::memset(data,0,sizeof(CImg<T>)*(size+1)); |
| delete[] data; |
| data = new_data; |
| } |
| } |
| return *this; |
| } |
| |
| CImgList get_remove(const unsigned int pos) const { |
| return CImgList<T>(*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<T>& img) { |
| if (size) { img.swap((*this)[size-1]); return remove(size-1); } |
| cimg::warn(true,"CImgl<%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<T>(*this).remove(); |
| } |
| |
| //! Reverse list order |
| CImgList& reverse() { |
| for (unsigned int l=0; l<size/2; l++) (*this)[l].swap((*this)[size-1-l]); |
| return *this; |
| } |
| |
| //! Get reversed list |
| CImgList get_reverse() const { |
| return CImgList<T>(*this).reverse(); |
| } |
| |
| //! Get a sub-list |
| const 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>::get_crop() : Cannot get a sub-list (%u->%u) from a list of %u images", |
| pixel_type(),i0,i1,size); |
| CImgList<T> 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].is_empty()) 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<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0)); |
| CImg<T> &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; i<N2; i++) { |
| if (j>i) cimg_forYZV(Ir,y,z,v) { cimg::swap(Ir(i,y,z,v),Ir(j,y,z,v)); cimg::swap(Ii(i,y,z,v),Ii(j,y,z,v)); |
| if (j<N2) { |
| const unsigned int ri = N-1-i, rj = N-1-j; |
| cimg::swap(Ir(ri,y,z,v),Ir(rj,y,z,v)); cimg::swap(Ii(ri,y,z,v),Ii(rj,y,z,v)); |
| }} |
| for (unsigned int m=N, n=N2; (j+=n)>=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<N; i+=delta) { |
| float wr = 1, wi = 0; |
| const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta), |
| ca = (float)std::cos(angle), |
| sa = (float)std::sin(angle); |
| for (unsigned int k=0; k<delta2; k++) { |
| const unsigned int j = i + k, nj = j + delta2; |
| cimg_forYZV(Ir,y,z,k) { |
| T &ir = Ir(j,y,z,k), &ii = Ii(j,y,z,k), &nir = Ir(nj,y,z,k), &nii = Ii(nj,y,z,k); |
| const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir; |
| nir = ir - tmpr; nii = ii - tmpi; |
| ir += tmpr; ii += tmpi; |
| } |
| const float nwr = wr*ca-wi*sa; |
| wi = wi*ca + wr*sa; |
| wr = nwr; |
| } |
| } |
| } |
| if (inverse) (*this)/=N; |
| } break; |
| |
| case 'y': { // Fourier along Y |
| const unsigned int N = Ir.height, N2 = (N>>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; i<N2; i++) { |
| if (j>i) cimg_forXZV(Ir,x,z,v) { cimg::swap(Ir(x,i,z,v),Ir(x,j,z,v)); cimg::swap(Ii(x,i,z,v),Ii(x,j,z,v)); |
| if (j<N2) { |
| const unsigned int ri = N-1-i, rj = N-1-j; |
| cimg::swap(Ir(x,ri,z,v),Ir(x,rj,z,v)); cimg::swap(Ii(x,ri,z,v),Ii(x,rj,z,v)); |
| }} |
| for (unsigned int m=N, n=N2; (j+=n)>=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<N; i+=delta) { |
| float wr = 1, wi = 0; |
| const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta), |
| ca = (float)std::cos(angle), sa = (float)std::sin(angle); |
| for (unsigned int k=0; k<delta2; k++) { |
| const unsigned int j = i + k, nj = j + delta2; |
| cimg_forXZV(Ir,x,z,k) { |
| T &ir = Ir(x,j,z,k), &ii = Ii(x,j,z,k), &nir = Ir(x,nj,z,k), &nii = Ii(x,nj,z,k); |
| const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir; |
| nir = ir - tmpr; nii = ii - tmpi; |
| ir += tmpr; ii += tmpi; |
| } |
| const float nwr = wr*ca-wi*sa; |
| wi = wi*ca + wr*sa; |
| wr = nwr; |
| } |
| } |
| } |
| if (inverse) (*this)/=N; |
| } break; |
| |
| case 'z': { // Fourier along Z |
| const unsigned int N = Ir.depth, N2 = (N>>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; i<N2; i++) { |
| if (j>i) cimg_forXYV(Ir,x,y,v) { cimg::swap(Ir(x,y,i,v),Ir(x,y,j,v)); cimg::swap(Ii(x,y,i,v),Ii(x,y,j,v)); |
| if (j<N2) { |
| const unsigned int ri = N-1-i, rj = N-1-j; |
| cimg::swap(Ir(x,y,ri,v),Ir(x,y,rj,v)); cimg::swap(Ii(x,y,ri,v),Ii(x,y,rj,v)); |
| }} |
| for (unsigned int m=N, n=N2; (j+=n)>=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<N; i+=delta) { |
| float wr = 1, wi = 0; |
| const float angle = (float)((inverse?+1:-1)*2*cimg::PI/delta), |
| ca = (float)std::cos(angle), sa = (float)std::sin(angle); |
| for (unsigned int k=0; k<delta2; k++) { |
| const unsigned int j = i + k, nj = j + delta2; |
| cimg_forXYV(Ir,x,y,k) { |
| T &ir = Ir(x,y,j,k), &ii = Ii(x,y,j,k), &nir = Ir(x,y,nj,k), &nii = Ii(x,y,nj,k); |
| const T tmpr = wr*nir - wi*nii, tmpi = wr*nii + wi*nir; |
| nir = ir - tmpr; nii = ii - tmpi; |
| ir += tmpr; ii += tmpi; |
| } |
| const float nwr = wr*ca-wi*sa; |
| wi = wi*ca + wr*sa; |
| wr = nwr; |
| } |
| } |
| } |
| if (inverse) (*this)/=N; |
| } break; |
| |
| default: throw CImgArgumentException("CImgList<%s>::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<typename cimg::largest<T,float>::type> get_FFT(const char axe,const bool inverse=false) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImgList<restype>(*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<T>(data[0].width,data[0].height,data[0].depth,data[0].dim,0)); |
| CImg<T> &Ir = data[0]; |
| |
| #ifdef cimg_use_fftw3 |
| CImg<T> &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<typename cimg::largest<T,float>::type> get_FFT(const bool inverse=false) const { |
| typedef typename cimg::largest<T,float>::type restype; |
| return CImgList<restype>(*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); |
| if (print_flag>0) cimglist_for(*this,l) { |
| std::sprintf(tmp,"%s[%d]",title?title:"CImgList",l); |
| data[l].print(tmp,print_flag); |
| } |
| return *this; |
| } |
| |
| //! Display informations about the list on the standart 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; l<n; l++) { \ |
| const bool endian = cimg::endian(); \ |
| j=0; while((i=std::fgetc(nfile))!='\n') tmp[j++]=(char)i; tmp[j]='\0'; \ |
| std::sscanf(tmp,"%u %u %u %u",&w,&h,&z,&k);\ |
| if (w*h*z*k>0) { \ |
| 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<T> 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>::get_load_cimg() : File '%s', Unknow CImg RAW header.", |
| pixel_type(),filename?filename:"(FILE*)"); |
| } |
| CImgList<T> 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>::get_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<float> st_slices; |
| CImgList<unsigned int> 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<float>::vector((float)sn,(float)pixsize,(float)sizex,(float)sizey,ri,rs,ss,0)); |
| unsigned int i; for (i=0; i<st_global.size && sn<=st_global[i][2]; i++); |
| if (i==st_global.size) st_global.insert(CImg<unsigned int>::vector(sizex,sizey,sn)); |
| else { |
| CImg<unsigned int> &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<T> dest; |
| { cimglist_for(st_global,l) { |
| const CImg<unsigned int>& vec = st_global[l]; |
| dest.insert(CImg<T>(vec[0],vec[1],vec[2])); |
| }} |
| |
| cimglist_for(st_slices,l) { |
| const CImg<float>& 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<unsigned char> buf(sizex,sizey); |
| cimg::fread(buf.data,sizex*sizey,file2); |
| if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); |
| CImg<T>& img = dest[imn]; |
| cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); |
| } break; |
| case 16: { |
| CImg<unsigned short> buf(sizex,sizey); |
| cimg::fread(buf.data,sizex*sizey,file2); |
| if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); |
| CImg<T>& img = dest[imn]; |
| cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); |
| } break; |
| case 32: { |
| CImg<unsigned int> buf(sizex,sizey); |
| cimg::fread(buf.data,sizex*sizey,file2); |
| if (cimg::endian()) cimg::endian_swap(buf.data,sizex*sizey); |
| CImg<T>& 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>::get_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>::get_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>::get_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>::get_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>::get_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>::get_load_yuv() : File '%s', given frame size (%u,%u) is invalid.", |
| pixel_type(),filename?filename:"(unknown)",sizex,sizey); |
| CImgList<T> res; |
| CImg<unsigned char> 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>::get_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>::get_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>::get_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>::get_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<typename tf,typename tc> |
| static CImgList<T> get_load_off(std::FILE *const file, const char *const filename, |
| CImgList<tf>& primitives, CImgList<tc>& colors, |
| const bool invert_faces=false) { |
| return CImg<T>::get_load_off(file,filename,primitives,colors,invert_faces).get_split('x'); |
| } |
| |
| //! Load from OFF file format |
| template<typename tf,typename tc> |
| static CImgList<T> get_load_off(const char *const filename, |
| CImgList<tf>& primitives, CImgList<tc>& colors, |
| const bool invert_faces=false) { |
| return get_load_off(0,filename,primitives,colors,invert_faces); |
| } |
| |
| //! In-place version of get_load_off() |
| template<typename tf,typename tc> |
| CImgList& load_off(std::FILE *const file, const char *const filename, CImgList<tf>& primitives, CImgList<tc>& 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<typename tf,typename tc> |
| CImgList& load_off(const char *const filename, CImgList<tf>& primitives, CImgList<tc>& 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<unsigned char> 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<T> 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<T>& 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<T> 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<typename tf, typename tc> |
| const CImgList& save_off(std::FILE *const file, const char *const filename, |
| const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const { |
| get_append('x').save_off(file,filename,primitives,colors,invert_faces); |
| return *this; |
| } |
| |
| //! Save an image list into a OFF file. |
| template<typename tf, typename tc> |
| const CImgList& save_off(const char *const filename, |
| const CImgList<tf>& primitives, const CImgList<tc>& colors, const bool invert_faces=false) const { |
| return save_off(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<T> image corresponding to the concatenation is returned. |
| **/ |
| CImg<T> get_append(const char axe='x',const char align='c') const { |
| if (is_empty()) return CImg<T>(); |
| unsigned int dx=0,dy=0,dz=0,dv=0,pos=0; |
| CImg<T> res; |
| switch(cimg::uncase(axe)) { |
| case 'x': { |
| cimglist_for(*this,l) { |
| const CImg<T>& 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 'p' : { cimglist_for(*this,ll) { res.draw_image((*this)[ll],pos,0,0,0); pos+=(*this)[ll].width; }} break; |
| case 'n' : { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],pos,dy-(*this)[ll].height,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].width; |
| }} break; |
| default : { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],pos,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2); |
| pos+=(*this)[ll].width; |
| }} break; |
| } |
| } break; |
| case 'y': { |
| cimglist_for(*this,l) { |
| const CImg<T>& 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 'p': { cimglist_for(*this,ll) { res.draw_image((*this)[ll],0,pos,0,0); pos+=(*this)[ll].height; }} break; |
| case 'n': { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],dx-(*this)[ll].width,pos,dz-(*this)[ll].depth,dv-(*this)[ll].dim); pos+=(*this)[ll].height; |
| }} break; |
| default : { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,pos,(dz-(*this)[ll].depth)/2,(dv-(*this)[ll].dim)/2); |
| pos+=(*this)[ll].height; |
| }} break; |
| } |
| } break; |
| case 'z': { |
| cimglist_for(*this,l) { |
| const CImg<T>& 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 'p': { cimglist_for(*this,ll) { res.draw_image((*this)[ll],0,0,pos,0); pos+=(*this)[ll].depth; }} break; |
| case 'n': { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,pos,dv-(*this)[ll].dim); pos+=(*this)[ll].depth; |
| }} break; |
| case 'c': { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,pos,(dv-(*this)[ll].dim)/2); |
| pos+=(*this)[ll].depth; |
| }} break; |
| } |
| } break; |
| case 'v': { |
| cimglist_for(*this,l) { |
| const CImg<T>& 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 'p': { cimglist_for(*this,ll) { res.draw_image((*this)[ll],0,0,0,pos); pos+=(*this)[ll].dim; }} break; |
| case 'n': { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],dx-(*this)[ll].width,dy-(*this)[ll].height,dz-(*this)[ll].depth,pos); pos+=(*this)[ll].dim; |
| }} break; |
| case 'c': { cimglist_for(*this,ll) { |
| res.draw_image((*this)[ll],(dx-(*this)[ll].width)/2,(dy-(*this)[ll].height)/2,(dz-(*this)[ll].depth)/2,pos); |
| pos+=(*this)[ll].dim; |
| }} break; |
| } |
| } break; |
| default: throw CImgArgumentException("CImg<%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<T> get_crop_font() const { |
| CImgList<T> res; |
| cimglist_for(*this,l) { |
| const CImg<T>& letter = (*this)[l]; |
| int xmin = letter.width, xmax = 0; |
| cimg_forXY(letter,x,y) if (letter(x,y)) { if (x<xmin) xmin=x; if (x>xmax) xmax=x; } |
| if (xmin>xmax) res.insert(CImg<T>(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<T>& crop_font() { |
| return get_crop_font().swap(*this); |
| } |
| |
| static CImgList<T> 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<T> res = CImgList<T>(256,w,h,1,3).insert(CImgList<T>(256,w,h,1,1)); |
| const unsigned int *ptr = font; |
| unsigned int m = 0, val = 0; |
| for (unsigned int y=0; y<h; y++) |
| for (unsigned int x=0; x<256*w; x++) { |
| m>>=1; if (!m) { m=0x80000000; val = *(ptr++); } |
| CImg<T>& 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<T> get_font(const unsigned int font_width, const bool variable_size=true) { |
| if (font_width<=11) { |
| static CImgList<T> font7x11, nfont7x11; |
| if (!variable_size && font7x11.is_empty()) font7x11 = get_font(cimg::font7x11,7,11,1,0,false); |
| if (variable_size && nfont7x11.is_empty()) nfont7x11 = get_font(cimg::font7x11,7,11,1,0,true); |
| return variable_size?nfont7x11:font7x11; |
| } |
| if (font_width<=13) { |
| static CImgList<T> font10x13, nfont10x13; |
| if (!variable_size && font10x13.is_empty()) font10x13 = get_font(cimg::font10x13,10,13,1,0,false); |
| if (variable_size && nfont10x13.is_empty()) nfont10x13 = get_font(cimg::font10x13,10,13,1,0,true); |
| return variable_size?nfont10x13:font10x13; |
| } |
| if (font_width<=17) { |
| static CImgList<T> font8x17, nfont8x17; |
| if (!variable_size && font8x17.is_empty()) font8x17 = get_font(cimg::font8x17,8,17,1,0,false); |
| if (variable_size && nfont8x17.is_empty()) nfont8x17 = get_font(cimg::font8x17,8,17,1,0,true); |
| return variable_size?nfont8x17:font8x17; |
| } |
| if (font_width<=19) { |
| static CImgList<T> font10x19, nfont10x19; |
| if (!variable_size && font10x19.is_empty()) font10x19 = get_font(cimg::font10x19,10,19,2,0,false); |
| if (variable_size && nfont10x19.is_empty()) nfont10x19 = get_font(cimg::font10x19,10,19,2,0,true); |
| return variable_size?nfont10x19:font10x19; |
| } |
| if (font_width<=24) { |
| static CImgList<T> font12x24, nfont12x24; |
| if (!variable_size && font12x24.is_empty()) font12x24 = get_font(cimg::font12x24,12,24,2,0,false); |
| if (variable_size && nfont12x24.is_empty()) nfont12x24 = get_font(cimg::font12x24,12,24,2,0,true); |
| return variable_size?nfont12x24:font12x24; |
| } |
| if (font_width<=32) { |
| static CImgList<T> font16x32, nfont16x32; |
| if (!variable_size && font16x32.is_empty()) font16x32 = get_font(cimg::font16x32,16,32,2,0,false); |
| if (variable_size && nfont16x32.is_empty()) nfont16x32 = get_font(cimg::font16x32,16,32,2,0,true); |
| return variable_size?nfont16x32:font16x32; |
| } |
| if (font_width<=38) { |
| static CImgList<T> font19x38, nfont19x38; |
| if (!variable_size && font19x38.is_empty()) font19x38 = get_font(cimg::font19x38,19,38,3,0,false); |
| if (variable_size && nfont19x38.is_empty()) nfont19x38 = get_font(cimg::font19x38,19,38,3,0,true); |
| return variable_size?nfont19x38:font19x38; |
| } |
| static CImgList<T> font29x57, nfont29x57; |
| if (!variable_size && font29x57.is_empty()) font29x57 = get_font(cimg::font29x57,29,57,5,0,false); |
| if (variable_size && nfont29x57.is_empty()) 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 { |
| get_append(axe,align).display(title,min_size,max_size); |
| 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 { |
| return display(" ",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; p<size; p++) { |
| const float x = (float)((*this)(p,0)), y = (float)((*this)(p,1)), z = (float)((*this)(p,2)); |
| if (x<xm) xm = x; |
| if (y<ym) ym = y; |
| if (z<zm) zm = z; |
| if (x>xM) 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<T>(*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 |
| # |
| # |
| # |
| #------------------------------------------ |
| */ |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator+(const CImg<t>& img, const t& val) { |
| return CImg<t>(img,false)+=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img,false)+=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator+(const t& val, const CImg<t>& img) { |
| return img+val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const t1& val, const CImg<t2>& img) { |
| return img+val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator+(const CImgList<t>& list, const t& val) { |
| return CImgList<t>(list)+=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)+=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator+(const t& val, const CImgList<t>& list) { |
| return list+val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const t1& val, const CImgList<t2>& list) { |
| return list+val; |
| } |
| #endif |
| |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img1, const CImg<t2>& img2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img1,false)+=img2; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImg<t1>& img, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)+=img; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list, const CImg<t2>& img) { |
| return img+list; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator+(const CImgList<t1>& list1, const CImgList<t2>& list2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list1)+=list2; |
| } |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator-(const CImg<t>& img, const t& val) { |
| return CImg<t>(img,false)-=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img,false)-=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator-(const t& val, const CImg<t>& img) { |
| return CImg<t>(img.width,img.height,img.depth,img.dim,val)-=img; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const t1& val, const CImg<t2>& img) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img.width,img.height,img.depth,img.dim,(restype)val)-=img; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator-(const CImgList<t>& list, const t& val) { |
| return CImgList<t>(list)-=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)-=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<double> operator-(const t& val, const CImgList<t>& list) { |
| CImgList<t> res(list.size); |
| cimglist_for(res,l) res[l] = val-list[l]; |
| return res; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const t1& val, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = val-list[l]; |
| return res; |
| } |
| #endif |
| |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img1, const CImg<t2>& img2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img1,false)-=img2; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImg<t1>& img, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = img-list[l]; |
| return res; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list, const CImg<t2>& img) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)-=img; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator-(const CImgList<t1>& list1, const CImgList<t2>& list2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list1)-=list2; |
| } |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator*(const CImg<t>& img, const double val) { |
| return CImg<t>(img,false)*=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img,false)*=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator*(const double val, const CImg<t>& img) { |
| return img*val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const t1& val, const CImg<t2>& img) { |
| return img*val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator*(const CImgList<t>& list, const double val) { |
| return CImgList<t>(list)*=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)*=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator*(const double val, const CImgList<t>& list) { |
| return list*val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const t1& val, const CImgList<t2>& list) { |
| return list*val; |
| } |
| #endif |
| |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img1, const CImg<t2>& img2) { |
| typedef typename cimg::largest<t1,t2>::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<restype> 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<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImg<t1>& img, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = img*list[l]; |
| return res; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list, const CImg<t2>& img) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = list[l]*img; |
| return res; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator*(const CImgList<t1>& list1, const CImgList<t2>& list2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(cimg::min(list1.size,list2.size)); |
| cimglist_for(res,l) res[l] = list1[l]*list2[l]; |
| return res; |
| } |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator/(const CImg<t>& img, const double val) { |
| return CImg<t>(img,false)/=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img,false)/=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImg<t> operator/(const double val, CImg<t>& img) { |
| return val*img.get_inverse(); |
| } |
| #else |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const t1& val, CImg<t2>& img) { |
| return val*img.get_inverse(); |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator/(const CImgList<t>& list, const double val) { |
| return CImgList<t>(list)/=val; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list, const t2& val) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)/=val; |
| } |
| #endif |
| |
| #ifdef cimg_use_visualcpp6 |
| template<typename t> inline CImgList<t> operator/(const double val, const CImgList<t>& list) { |
| CImgList<t> res(list.size); |
| cimglist_for(res,l) res[l] = val/list[l]; |
| return res; |
| } |
| #else |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const t1& val, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = val/list[l]; |
| return res; |
| } |
| #endif |
| |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img1, const CImg<t2>& img2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImg<restype>(img1,false)*=img2.get_inverse(); |
| } |
| |
| template<typename t1, typename t2> inline CImg<typename cimg::largest<t1,t2>::type> operator/(const CImg<t1>& img, const CImgList<t2>& list) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| CImgList<restype> res(list.size); |
| cimglist_for(res,l) res[l] = img/list[l]; |
| return res; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list, const CImg<t2>& img) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list)/=img; |
| } |
| |
| template<typename t1, typename t2> inline CImgList<typename cimg::largest<t1,t2>::type> operator/(const CImgList<t1>& list1, const CImgList<t2>& list2) { |
| typedef typename cimg::largest<t1,t2>::type restype; |
| return CImgList<restype>(list1)/=list2; |
| } |
| |
| 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<typename t> |
| 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<t>& 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<unsigned char> buttons, cbuttons, sbuttons; |
| if (button1_txt) { buttons.insert(CImg<unsigned char>().draw_text(button1_txt,0,0,black,gray,13)); |
| if (button2_txt) { buttons.insert(CImg<unsigned char>().draw_text(button2_txt,0,0,black,gray,13)); |
| if (button3_txt) { buttons.insert(CImg<unsigned char>().draw_text(button3_txt,0,0,black,gray,13)); |
| if (button4_txt) { buttons.insert(CImg<unsigned char>().draw_text(button4_txt,0,0,black,gray,13)); |
| if (button5_txt) { buttons.insert(CImg<unsigned char>().draw_text(button5_txt,0,0,black,gray,13)); |
| if (button6_txt) { buttons.insert(CImg<unsigned char>().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<unsigned char> button = CImg<unsigned char>(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<unsigned char> sbutton = CImg<unsigned char>(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<unsigned char> cbutton = CImg<unsigned char>(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<unsigned char>(cbutton).draw_image(buttons[ll],1+(bw-buttons[ll].dimx())/2,1+(bh-buttons[ll].dimy())/2)); |
| sbuttons.insert(CImg<unsigned char>(sbutton).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2)); |
| buttons[ll] = CImg<unsigned char>(button).draw_image(buttons[ll],(bw-buttons[ll].dimx())/2,(bh-buttons[ll].dimy())/2); |
| } |
| |
| CImg<unsigned char> canvas; |
| if (msg) canvas = CImg<unsigned char>().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<unsigned char>(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<unsigned char>(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<unsigned char>(canvas).draw_image(cbuttons[clicked],xbuttons[clicked],by).display(disp); |
| else { |
| if (selected>=0) CImg<unsigned char>(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.is_closed) 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<unsigned char>::get_logo40x38(),centering); |
| } |
| |
| |
| // Inner routine used by the Marching cube algorithm |
| template<typename t> inline int _marching_cubes_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& indices2, |
| const unsigned int x, const unsigned int y, const unsigned int nx, const unsigned int ny) { |
| 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<typename tfunc, typename tp, typename tf> |
| 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<tp>& points, CImgList<tf>& 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<int> indices1(nx,ny,1,3,-1), indices2(indices1); |
| CImg<float> 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<nzm1; ++zi, Z=nZ, nZ+=resz) { |
| Y = y0; nY = Y + resy; |
| indices2.fill(-1); |
| for (unsigned int yi=0, nyi=1; yi<nym1; ++yi, ++nyi, Y=nY, nY+=resy) { |
| X = x0; nX = X + resx; |
| for (unsigned int xi=0, nxi=1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) { |
| |
| // Determine cube configuration |
| const float |
| val0 = values1(xi,yi), val1 = values1(nxi,yi), val2 = values1(nxi,nyi), val3 = values1(xi,nyi), |
| val4 = values2(xi,yi) = (float)func(X,Y,nZ), |
| val5 = values2(nxi,yi) = (float)func(nX,Y,nZ), |
| val6 = values2(nxi,nyi) = (float)func(nX,nY,nZ), |
| val7 = values2(xi,nyi) = (float)func(X,nY,nZ); |
| |
| const unsigned int configuration = |
| (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0) | |
| (val4<isovalue?16:0) | (val5<isovalue?32:0) | (val6<isovalue?64:0) | (val7<isovalue?128:0), |
| edge = edges[configuration]; |
| |
| // Compute intersection points |
| if (edge) { |
| if ((edge&1) && indices1(xi,yi,0)<0) { |
| const float Xi = X + (isovalue-val0)*resx/(val1-val0); |
| indices1(xi,yi,0) = points.size; |
| points.insert(CImg<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tp>::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<tf>::vector(i0,i1,i2)); |
| else primitives.insert(CImg<tf>::vector(i0,i2,i1)); |
| } |
| } |
| } |
| } |
| cimg::swap(values1,values2); |
| cimg::swap(indices1,indices2); |
| } |
| } |
| |
| // Inner routine used by the Marching square algorithm |
| template<typename t> inline int _marching_squares_indice(const unsigned int edge, const CImg<t>& indices1, const CImg<t>& 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<typename tfunc, typename tp, typename tf> |
| 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<tp>& points, CImgList<tf>& 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<int> indices1(nx,1,1,2,-1), indices2(nx,1,1,2); |
| CImg<float> 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<nym1; ++yi, ++nyi, Y=nY, nY+=resy) { |
| X = x0; nX = X + resx; |
| indices2.fill(-1); |
| for (unsigned int xi=0, nxi=1; xi<nxm1; ++xi, ++nxi, X=nX, nX+=resx) { |
| |
| // Determine cube configuration |
| const float |
| val0 = values1(xi), val1 = values1(nxi), |
| val2 = values2(nxi) = (float)func(nX,nY), |
| val3 = values2(xi) = (float)func(X,nY); |
| |
| const unsigned int configuration = (val0<isovalue?1:0) | (val1<isovalue?2:0) | (val2<isovalue?4:0) | (val3<isovalue?8:0), |
| edge = edges[configuration]; |
| |
| // Compute intersection points |
| if (edge) { |
| if ((edge&1) && indices1(xi,0)<0) { |
| const float Xi = X + (isovalue-val0)*resx/(val1-val0); |
| indices1(xi,0) = points.size; |
| points.insert(CImg<tp>::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<tp>::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<tp>::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<tp>::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<tf>::vector(i0,i1)); |
| } |
| } |
| } |
| values1.swap(values2); |
| indices1.swap(indices2); |
| } |
| } |
| |
| // End of cimg:: namespace |
| } |
| |
| |
| // End of cimg_library:: namespace |
| } |
| |
| #ifdef std |
| #undef std |
| #endif |
| |
| #endif |
| |
| // Local Variables: |
| // mode: c++ |
| // End: |