[cimg] 01/01: New upstream version 1.7.9+dfsg

Andreas Tille tille at debian.org
Mon Dec 5 20:30:27 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to annotated tag upstream/1.7.9+dfsg
in repository cimg.

commit 7968fe362f4e7d72d6bb3c3534db274bd4981189
Author: Andreas Tille <tille at debian.org>
Date:   Mon Dec 5 19:40:19 2016 +0100

    New upstream version 1.7.9+dfsg
---
 CImg.h                       | 1121 ++++++++++++++++++++++++++++--------------
 examples/CImg_demo.cpp       |    2 +-
 examples/edge_explorer2d.cpp |    8 +-
 html/header.html             |    4 +-
 html/header_reference.html   |    4 +-
 html/img/CImgLogo2.jpg       |  Bin 70868 -> 73652 bytes
 html/img/postcard65.jpg      |  Bin 0 -> 18325 bytes
 html/index.shtml             |    5 +-
 8 files changed, 763 insertions(+), 381 deletions(-)

diff --git a/CImg.h b/CImg.h
index 8f91cb9..aabbb23 100644
--- a/CImg.h
+++ b/CImg.h
@@ -54,7 +54,7 @@
 
 // Set version number of the library.
 #ifndef cimg_version
-#define cimg_version 178
+#define cimg_version 179
 
 /*-----------------------------------------------------------
  #
@@ -197,7 +197,7 @@
 #endif
 
 // Convenient macro to define pragma
-#ifdef _MSC_VER_
+#ifdef _MSC_VER
 #define cimg_pragma(x) __pragma(x)
 #else
 #define cimg_pragma(x) _Pragma(#x)
@@ -211,16 +211,21 @@
 #define cimg_ulong UINT_PTR
 #define cimg_long INT_PTR
 #else
-#if UINTPTR_MAX==0xffffffff
+#if UINTPTR_MAX==0xffffffff || defined(__arm__) || defined(_M_ARM)
 #define cimg_uint64 unsigned long long
 #define cimg_int64 long long
 #else
 #define cimg_uint64 unsigned long
 #define cimg_int64 long
 #endif
+#if defined(__arm__) || defined(_M_ARM)
+#define cimg_ulong unsigned long long
+#define cimg_long long long
+#else
 #define cimg_ulong unsigned long
 #define cimg_long long
 #endif
+#endif
 
 // Configure filename separator.
 //
@@ -2549,6 +2554,7 @@ namespace cimg_library_suffixed {
       static T inf() { return max(); }
       static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; }
       static const char* format() { return "%s"; }
+      static const char* format_s() { return "%s"; }
       static const char* format(const T& val) { static const char *const s = "unknown"; cimg::unused(val); return s; }
     };
 
@@ -2563,6 +2569,7 @@ namespace cimg_library_suffixed {
       static bool is_inf() { return false; }
       static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; }
       static const char* format() { return "%s"; }
+      static const char* format_s() { return "%s"; }
       static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; }
     };
 
@@ -2577,6 +2584,7 @@ namespace cimg_library_suffixed {
       static unsigned char cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }
       static const char* format() { return "%u"; }
+      static const char* format_s() { return "%u"; }
       static unsigned int format(const unsigned char val) { return (unsigned int)val; }
     };
 
@@ -2592,6 +2600,7 @@ namespace cimg_library_suffixed {
       static char cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; }
       static const char* format() { return "%u"; }
+      static const char* format_s() { return "%u"; }
       static unsigned int format(const char val) { return (unsigned int)val; }
     };
 #else
@@ -2605,6 +2614,7 @@ namespace cimg_library_suffixed {
       static char inf() { return max(); }
       static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; }
       static const char* format() { return "%d"; }
+      static const char* format_s() { return "%d"; }
       static int format(const char val) { return (int)val; }
     };
 #endif
@@ -2620,6 +2630,7 @@ namespace cimg_library_suffixed {
       static signed char cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(signed char)val; }
       static const char* format() { return "%d"; }
+      static const char* format_s() { return "%d"; }
       static int format(const signed char val) { return (int)val; }
     };
 
@@ -2634,6 +2645,7 @@ namespace cimg_library_suffixed {
       static unsigned short cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; }
       static const char* format() { return "%u"; }
+      static const char* format_s() { return "%u"; }
       static unsigned int format(const unsigned short val) { return (unsigned int)val; }
     };
 
@@ -2647,6 +2659,7 @@ namespace cimg_library_suffixed {
       static short inf() { return max(); }
       static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; }
       static const char* format() { return "%d"; }
+      static const char* format_s() { return "%d"; }
       static int format(const short val) { return (int)val; }
     };
 
@@ -2661,6 +2674,7 @@ namespace cimg_library_suffixed {
       static unsigned int cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; }
       static const char* format() { return "%u"; }
+      static const char* format_s() { return "%u"; }
       static unsigned int format(const unsigned int val) { return val; }
     };
 
@@ -2674,6 +2688,7 @@ namespace cimg_library_suffixed {
       static int inf() { return max(); }
       static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; }
       static const char* format() { return "%d"; }
+      static const char* format_s() { return "%d"; }
       static int format(const int val) { return val; }
     };
 
@@ -2688,6 +2703,7 @@ namespace cimg_library_suffixed {
       static cimg_uint64 cut(const double val) {
         return val<(double)min()?min():val>(double)max()?max():(cimg_uint64)val; }
       static const char* format() { return "%lu"; }
+      static const char* format_s() { return "%lu"; }
       static unsigned long format(const cimg_uint64 val) { return (unsigned long)val; }
     };
 
@@ -2703,6 +2719,7 @@ namespace cimg_library_suffixed {
         return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val;
       }
       static const char* format() { return "%ld"; }
+      static const char* format_s() { return "%ld"; }
       static long format(const long val) { return (long)val; }
     };
 
@@ -2740,7 +2757,8 @@ namespace cimg_library_suffixed {
 #endif
       }
       static double cut(const double val) { return val; }
-      static const char* format() { return "%.16g"; }
+      static const char* format() { return "%.17g"; }
+      static const char* format_s() { return "%g"; }
       static double format(const double val) { return val; }
     };
 
@@ -2767,7 +2785,8 @@ namespace cimg_library_suffixed {
       static float nan() { return (float)cimg::type<double>::nan(); }
       static float cut(const double val) { return (float)val; }
       static float cut(const float val) { return (float)val; }
-      static const char* format() { return "%.16g"; }
+      static const char* format() { return "%.9g"; }
+      static const char* format_s() { return "%g"; }
       static double format(const float val) { return (double)val; }
     };
 
@@ -2793,7 +2812,8 @@ namespace cimg_library_suffixed {
       static long double inf() { return max()*max(); }
       static long double nan() { const long double val_nan = -std::sqrt(-1.0L); return val_nan; }
       static long double cut(const long double val) { return val; }
-      static const char* format() { return "%.16g"; }
+      static const char* format() { return "%.17g"; }
+      static const char* format_s() { return "%g"; }
       static double format(const long double val) { return (double)val; }
     };
 
@@ -2820,7 +2840,8 @@ namespace cimg_library_suffixed {
       static half inf() { return max()*max(); }
       static half nan() { const half val_nan = (half)-std::sqrt(-1.0); return val_nan; }
       static half cut(const double val) { return (half)val; }
-      static const char* format() { return "%.16g"; }
+      static const char* format() { return "%.9g"; }
+      static const char* format_s() { return "%g"; }
       static double format(const half val) { return (double)val; }
     };
 #endif
@@ -4543,7 +4564,7 @@ namespace cimg_library_suffixed {
     // Use the system RNG.
     inline void srand() {
       const unsigned int t = (unsigned int)cimg::time();
-#if cimg_OS==1
+#if cimg_OS==1 || defined(__BORLANDC__)
       std::srand(t + (unsigned int)getpid());
 #elif cimg_OS==2
       std::srand(t + (unsigned int)_getpid());
@@ -5249,8 +5270,8 @@ namespace cimg_library_suffixed {
 
     inline double _fibonacci(int exp) {
       double
-        base = 1.6180339887498948482045868343656, // (1 + sqrt(5))/2;
-        result = 0.44721359549995793928183473374626; // 1 / sqrt(5)
+        base = (1 + std::sqrt(5.0))/2,
+        result = 1/std::sqrt(5.0);
       while (exp) {
         if (exp&1) result*=base;
         exp>>=1;
@@ -5508,7 +5529,8 @@ namespace cimg_library_suffixed {
       for (unsigned int k = 0; k<8; ++k) {
         const int v = (int)cimg::rand(65535)%3;
         randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)):
-                             (v==1?('a' + ((int)cimg::rand(65535)%26)):('A' + ((int)cimg::rand(65535)%26))));
+                             (v==1?('a' + ((int)cimg::rand(65535)%26)):
+                              ('A' + ((int)cimg::rand(65535)%26))));
       }
       cimg::mutex(6,0);
       return randomid;
@@ -5547,7 +5569,11 @@ namespace cimg_library_suffixed {
         res = (*mode=='r')?cimg::_stdin():cimg::_stdout();
 #if cimg_OS==2
         if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode.
+#ifdef __BORLANDC__
+          if (setmode(_fileno(res),0x8000)==-1) res = 0;
+#else
           if (_setmode(_fileno(res),0x8000)==-1) res = 0;
+#endif
         }
 #endif
       } else res = std_fopen(path,mode);
@@ -6565,6 +6591,15 @@ namespace cimg_library_suffixed {
       assign(disp);
     }
 
+    //! Take a screenshot.
+    /**
+       \param[out] img Output screenshot. Can be empty on input
+    **/
+    template<typename T>
+    static void screenshot(CImg<T>& img) {
+      return screenshot(0,0,cimg::type<int>::max(),cimg::type<int>::max(),img);
+    }
+
 #if cimg_display==0
 
     static void _no_display_exception() {
@@ -7801,6 +7836,21 @@ namespace cimg_library_suffixed {
       return assign();
     }
 
+
+    //! Take a snapshot of the current screen content.
+    /**
+       \param x0 X-coordinate of the upper left corner.
+       \param y0 Y-coordinate of the upper left corner.
+       \param x1 X-coordinate of the lower right corner.
+       \param y1 Y-coordinate of the lower right corner.
+       \param[out] img Output screenshot. Can be empty on input
+    **/
+    template<typename T>
+    static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
+      cimg::unused(x0,y0,x1,y1,&img);
+      _no_display_exception();
+    }
+
     //! Take a snapshot of the associated window content.
     /**
        \param[out] img Output snapshot. Can be empty on input.
@@ -9016,6 +9066,56 @@ namespace cimg_library_suffixed {
     }
 
     template<typename T>
+    static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
+      img.assign();
+      Display *dpy = cimg::X11_attr().display;
+      cimg_lock_display();
+      if (!dpy) {
+        dpy = XOpenDisplay(0);
+        if (!dpy)
+          throw CImgDisplayException("CImgDisplay::screenshot(): Failed to open X11 display.");
+      }
+      Window root = DefaultRootWindow(dpy);
+      XWindowAttributes gwa;
+      XGetWindowAttributes(dpy,root,&gwa);
+      const int width = gwa.width, height = gwa.height;
+      int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1;
+      if (_x0>_x1) cimg::swap(_x0,_x1);
+      if (_y0>_y1) cimg::swap(_y0,_y1);
+
+      XImage *image = 0;
+      if (_x1>=0 && _x0<width && _y1>=0 && _y0<height) {
+        _x0 = cimg::max(_x0,0);
+        _y0 = cimg::max(_y0,0);
+        _x1 = cimg::min(_x1,width - 1);
+        _y1 = cimg::min(_y1,height - 1);
+        image = XGetImage(dpy,root,_x0,_y0,_x1 - _x0 + 1,_y1 - _y0 + 1,AllPlanes,ZPixmap);
+
+        if (image) {
+          const unsigned long
+            red_mask = image->red_mask,
+            green_mask = image->green_mask,
+            blue_mask = image->blue_mask;
+          img.assign(image->width,image->height,1,3);
+          T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2);
+          cimg_forXY(img,x,y) {
+            const unsigned long pixel = XGetPixel(image,x,y);
+            *(pR++) = (T)((pixel & red_mask)>>16);
+            *(pG++) = (T)((pixel & green_mask)>>8);
+            *(pB++) = (T)(pixel & blue_mask);
+          }
+          XDestroyImage(image);
+        }
+      }
+      if (!cimg::X11_attr().display) XCloseDisplay(dpy);
+      cimg_unlock_display();
+      if (img.is_empty())
+        throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot "
+                                   "with coordinates (%d,%d)-(%d,%d).",
+                                   x0,y0,x1,y1);
+    }
+
+    template<typename T>
     const CImgDisplay& snapshot(CImg<T>& img) const {
       if (is_empty()) { img.assign(); return *this; }
       const unsigned char *ptrs = (unsigned char*)_data;
@@ -9189,7 +9289,7 @@ namespace cimg_library_suffixed {
         disp->_mouse_x = disp->_mouse_y = -1;
         disp->_is_mouse_tracked = false;
         cimg::mutex(15);
-	while (ShowCursor(TRUE)<0);
+	while (ShowCursor(TRUE)<0) {}
         cimg::mutex(15,0);
       } break;
       case WM_LBUTTONDOWN :
@@ -9672,6 +9772,65 @@ namespace cimg_library_suffixed {
     }
 
     template<typename T>
+    static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg<T>& img) {
+      img.assign();
+      HDC hScreen = GetDC(GetDesktopWindow());
+      if (hScreen) {
+        const int
+          width = GetDeviceCaps(hScreen,HORZRES),
+          height = GetDeviceCaps(hScreen,VERTRES);
+        int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1;
+        if (_x0>_x1) cimg::swap(_x0,_x1);
+        if (_y0>_y1) cimg::swap(_y0,_y1);
+        if (_x1>=0 && _x0<width && _y1>=0 && _y0<height) {
+          _x0 = cimg::max(_x0,0);
+          _y0 = cimg::max(_y0,0);
+          _x1 = cimg::min(_x1,width - 1);
+          _y1 = cimg::min(_y1,height - 1);
+          const int bw = _x1 - _x0 + 1, bh = _y1 - _y0 + 1;
+          HDC hdcMem = CreateCompatibleDC(hScreen);
+          if (hdcMem) {
+            HBITMAP hBitmap = CreateCompatibleBitmap(hScreen,bw,bh);
+            if (hBitmap) {
+              HGDIOBJ hOld = SelectObject(hdcMem,hBitmap);
+              if (hOld && BitBlt(hdcMem,0,0,bw,bh,hScreen,_x0,_y0,SRCCOPY) && SelectObject(hdcMem,hOld)) {
+                BITMAPINFOHEADER bmi = {0};
+                bmi.biSize = sizeof(BITMAPINFOHEADER);
+                bmi.biPlanes = 1;
+                bmi.biBitCount = 32;
+                bmi.biWidth = bw;
+                bmi.biHeight = -bh;
+                bmi.biCompression = BI_RGB;
+                bmi.biSizeImage = 0;
+
+                unsigned char *buf = new unsigned char[4*bw*bh];
+                if (GetDIBits(hdcMem,hBitmap,0,bh,buf,(BITMAPINFO*)&bmi,DIB_RGB_COLORS)) {
+                  img.assign(bw,bh,1,3);
+                  const unsigned char *ptrs = buf;
+                  T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2);
+                  cimg_forXY(img,x,y) {
+                    *(pR++) = (T)ptrs[2];
+                    *(pG++) = (T)ptrs[1];
+                    *(pB++) = (T)ptrs[0];
+                    ptrs+=4;
+                  }
+                }
+                delete[] buf;
+              }
+              DeleteObject(hBitmap);
+            }
+            DeleteDC(hdcMem);
+          }
+        }
+        ReleaseDC(GetDesktopWindow(),hScreen);
+      }
+      if (img.is_empty())
+        throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot "
+                                   "with coordinates (%d,%d)-(%d,%d).",
+                                   x0,y0,x1,y1);
+    }
+
+    template<typename T>
     const CImgDisplay& snapshot(CImg<T>& img) const {
       if (is_empty()) { img.assign(); return *this; }
       const unsigned int *ptrs = _data;
@@ -13517,7 +13676,6 @@ namespace cimg_library_suffixed {
       const T *ptrs = _data;
       unsigned int string_size = 0;
       const char *const _format = format?format:cimg::type<T>::format();
-
       for (ulongT off = 0, siz = size(); off<siz && string_size<=max_size; ++off) {
         const unsigned int printed_size = 1U + cimg_snprintf(s_item,s_item._width,_format,
                                                              cimg::type<T>::format(*(ptrs++)));
@@ -14382,16 +14540,16 @@ namespace cimg_library_suffixed {
       CImg<T> &imgout;
       CImgList<T>& listout;
 
-      CImg<doubleT> _img_stats, &img_stats;
+      CImg<doubleT> _img_stats, &img_stats, constcache_vals;
       CImgList<doubleT> _list_stats, &list_stats, _list_median, &list_median;
-      CImg<uintT> mem_img_stats;
+      CImg<uintT> mem_img_stats, constcache_inds;
 
       CImg<uintT> level, variable_pos, reserved_label;
       CImgList<charT> variable_def, macro_def, macro_body;
       CImgList<boolT> macro_body_is_string;
       char *user_macro;
 
-      unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim, break_type;
+      unsigned int mempos, mem_img_median, debug_indent, init_size, result_dim, break_type, constcache_size;
       bool is_parallelizable, need_input_copy;
       double *result;
       const char *const calling_function, *s_op, *ss_op;
@@ -14435,7 +14593,7 @@ namespace cimg_library_suffixed {
         imgin(img_input),listin(list_input?*list_input:CImgList<T>::const_empty()),
         imgout(img_output?*img_output:CImg<T>::empty()),listout(list_output?*list_output:CImgList<T>::empty()),
         img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),user_macro(0),
-        mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),break_type(0),
+        mem_img_median(~0U),debug_indent(0),init_size(0),result_dim(0),break_type(0),constcache_size(0),
         is_parallelizable(true),need_input_copy(false),calling_function(funcname?funcname:"cimg_math_parser") {
         if (!expression || !*expression)
           throw CImgArgumentException("[_cimg_math_parser] "
@@ -14511,11 +14669,13 @@ namespace cimg_library_suffixed {
           else mem[ind_result] = cimg::type<double>::nan();
         }
 
-        // Free resources used for parsing and prepare for evaluation.
-        if (_cimg_mp_is_vector(ind_result)) result_dim = _cimg_mp_vector_size(ind_result);
+        // Free resources used for compiling expression and prepare evaluation.
+        result_dim = _cimg_mp_vector_size(ind_result);
         mem.resize(mempos,1,1,1,-1);
         result = mem._data + ind_result;
         memtype.assign();
+        constcache_vals.assign();
+        constcache_inds.assign();
         level.assign();
         variable_pos.assign();
         reserved_label.assign();
@@ -14524,7 +14684,7 @@ namespace cimg_library_suffixed {
         opcode.assign();
         opcode._is_shared = true;
 
-        // Execute init() function if any specified.
+        // Execute init() bloc if any specified.
         p_code_begin = code._data + init_size;
         if (init_size) {
           mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0;
@@ -14542,7 +14702,8 @@ namespace cimg_library_suffixed {
         imgin(CImg<T>::const_empty()),listin(CImgList<T>::const_empty()),
         imgout(CImg<T>::empty()),listout(CImgList<T>::empty()),
         img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),debug_indent(0),
-        result_dim(0),break_type(0),is_parallelizable(true),need_input_copy(false),calling_function(0) {
+        result_dim(0),break_type(0),constcache_size(0),is_parallelizable(true),need_input_copy(false),
+        calling_function(0) {
         mem.assign(1 + _cimg_mp_slot_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()()
         result = mem._data;
       }
@@ -14551,7 +14712,7 @@ namespace cimg_library_suffixed {
         mem(mp.mem),code(mp.code),p_code_begin(mp.p_code_begin),p_code_end(mp.p_code_end),p_break(mp.p_break),
         imgin(mp.imgin),listin(mp.listin),imgout(mp.imgout),listout(mp.listout),img_stats(mp.img_stats),
         list_stats(mp.list_stats),list_median(mp.list_median),debug_indent(0),result_dim(mp.result_dim),
-        break_type(0),is_parallelizable(mp.is_parallelizable),need_input_copy(mp.need_input_copy),
+        break_type(0),constcache_size(0),is_parallelizable(mp.is_parallelizable),need_input_copy(mp.need_input_copy),
         result(mem._data + (mp.result - mp.mem._data)),calling_function(0) {
 #ifdef cimg_use_openmp
         mem[17] = omp_get_thread_num();
@@ -14566,18 +14727,18 @@ namespace cimg_library_suffixed {
         unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string
         CImg<uintT> res(expr._width - 1);
         unsigned int *pd = res._data;
-        int lv = 0;
-        for (const char *ps = expr._data; *ps && lv>=0; ++ps) {
+        int level = 0;
+        for (const char *ps = expr._data; *ps && level>=0; ++ps) {
           if (!next_is_escaped && *ps=='\\') next_is_escaped = true;
           if (!is_escaped && *ps=='\'') { // Non-escaped character
             if (!mode && ps>expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string
             else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string
             else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string
           }
-          *(pd++) = (unsigned int)(mode>=1 || is_escaped?lv + (mode==1):
-                                   *ps=='(' || *ps=='['?lv++:
-                                   *ps==')' || *ps==']'?--lv:
-                                   lv);
+          *(pd++) = (unsigned int)(mode>=1 || is_escaped?level + (mode==1):
+                                   *ps=='(' || *ps=='['?level++:
+                                   *ps==')' || *ps==']'?--level:
+                                   level);
           mode = next_mode;
           is_escaped = next_is_escaped;
           next_is_escaped = false;
@@ -14589,7 +14750,7 @@ namespace cimg_library_suffixed {
                                       pixel_type(),_cimg_mp_calling_function,
                                       expr._data);
         }
-        if (lv!=0) {
+        if (level) {
           cimg::strellipsize(expr,64);
           throw CImgArgumentException("[_cimg_math_parser] "
                                       "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
@@ -15201,7 +15362,7 @@ namespace cimg_library_suffixed {
 
               if (arg1==~0U) { // Create new variable
                 if (_cimg_mp_is_vector(arg2)) { // Vector variable
-                  arg1 = vector_copy(arg2);
+                  arg1 = is_comp_vector(arg2)?arg2:vector_copy(arg2);
                   set_variable_vector(arg1);
                 } else { // Scalar variable
                   if (is_const) arg1 = arg2;
@@ -15396,7 +15557,7 @@ namespace cimg_library_suffixed {
                                         s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
           }
 
-        // Apply unary/binary/ternary operators. The operator precedences should be roughly the same as in C++.
+        // Apply unary/binary/ternary operators. The operator precedences should be the same as in C++.
         for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
           if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&
               level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=)
@@ -15930,7 +16091,7 @@ namespace cimg_library_suffixed {
                 pos = vector(2);
                 CImg<ulongT>::vector((ulongT)mp_complex_mul,pos,arg1,arg2).move_to(code);
                 _cimg_mp_return(pos);
-              } else { // Matrix multiplication
+              } else { // Particular case of matrix multiplication
                 p1 = _cimg_mp_vector_size(arg1);
                 p2 = _cimg_mp_vector_size(arg2);
                 arg4 = p1/p2;
@@ -15985,6 +16146,12 @@ namespace cimg_library_suffixed {
             _cimg_mp_op("Operator '*'");
             arg1 = compile(ss,s,depth1,0);
             arg2 = compile(s + 1,se,depth1,0);
+            p2 = _cimg_mp_vector_size(arg2);
+            if (p2>0 && _cimg_mp_vector_size(arg1)==p2*p2) { // Particular case of matrix multiplication
+              pos = vector(p2);
+              CImg<ulongT>::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,p2,p2,1).move_to(code);
+              _cimg_mp_return(pos);
+            }
             _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
             if (arg2==1) _cimg_mp_return(arg1);
             if (arg1==1) _cimg_mp_return(arg2);
@@ -16263,6 +16430,8 @@ namespace cimg_library_suffixed {
         if (*se1==']' && *ss!='[') {
           _cimg_mp_op("Value accessor '[]'");
           is_relative = *ss=='j' || *ss=='J';
+          s0 = std::strchr(ss,'[');
+          if (s0>ss && *(s0 - 1)==' ') cimg::swap(*s0,*(s0 - 1)); // Allow one space before opening bracket
 
           if ((*ss=='I' || *ss=='J') && *ss1=='[' &&
               (reserved_label[*ss]==~0U || !_cimg_mp_is_vector(reserved_label[*ss]))) { // Image value as a vector
@@ -16400,8 +16569,10 @@ namespace cimg_library_suffixed {
         // Look for a function call, an access to image value, or a parenthesis.
         if (*se1==')') {
           if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref)); // Simple parentheses
-          is_relative = *ss=='j' || *ss=='J';
           _cimg_mp_op("Value accessor '()'");
+          is_relative = *ss=='j' || *ss=='J';
+          s0 = std::strchr(ss,'(');
+          if (s0>ss && *(s0 - 1)==' ') cimg::swap(*s0,*(s0 - 1)); // Allow one space before opening brace
 
           // I/J(_#ind,_x,_y,_z,_interpolation,_boundary)
           if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar
@@ -16651,6 +16822,14 @@ namespace cimg_library_suffixed {
                 _cimg_mp_return(_cimg_mp_slot_nan);
               }
             }
+
+            if (!std::strncmp(ss,"breakpoint(",11)) { // Break point (for abort test)
+              _cimg_mp_op("Function 'breakpoint()'");
+              if (pexpr[se2 - expr._data]=='(') { // no arguments?
+                CImg<ulongT>::vector((ulongT)mp_breakpoint,_cimg_mp_slot_nan).move_to(code);
+                _cimg_mp_return(_cimg_mp_slot_nan);
+              }
+            }
             break;
 
           case 'c' :
@@ -17031,7 +17210,6 @@ namespace cimg_library_suffixed {
 
             if (!std::strncmp(ss,"dowhile",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // Do..while
               _cimg_mp_op("Function 'dowhile()'");
-              if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
               s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
               arg1 = code._width;
               arg6 = mempos;
@@ -17157,7 +17335,7 @@ namespace cimg_library_suffixed {
               _cimg_mp_check_matrix_square(arg1,1);
               p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
               pos = vector((p1 + 1)*p1);
-              CImg<ulongT>::vector((ulongT)mp_eig,pos,arg1,p1).move_to(code);
+              CImg<ulongT>::vector((ulongT)mp_matrix_eig,pos,arg1,p1).move_to(code);
               _cimg_mp_return(pos);
             }
 
@@ -17239,7 +17417,6 @@ namespace cimg_library_suffixed {
 
             if (*ss1=='o' && *ss2=='r' && (*ss3=='(' || (*ss3 && *ss3<=' ' && *ss4=='('))) { // For loop
               _cimg_mp_op("Function 'for()'");
-              if (*ss3<=' ') cimg::swap(*ss3,*ss4); // Allow space before opening brace
               s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
               s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
               s3 = s2 + 1; while (s3<se1 && (*s3!=',' || level[s3 - expr._data]!=clevel1)) ++s3;
@@ -17287,7 +17464,6 @@ namespace cimg_library_suffixed {
           case 'i' :
             if (*ss1=='f' && (*ss2=='(' || (*ss2 && *ss2<=' ' && *ss3=='('))) { // If..then[..else.]
               _cimg_mp_op("Function 'if()'");
-              if (*ss2<=' ') cimg::swap(*ss2,*ss3); // Allow space before opening brace
               s1 = ss3; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
               s2 = s1 + 1; while (s2<se1 && (*s2!=',' || level[s2 - expr._data]!=clevel1)) ++s2;
               arg1 = compile(ss3,s1,depth1,0);
@@ -17336,11 +17512,15 @@ namespace cimg_library_suffixed {
             if (!std::strncmp(ss,"inv(",4)) { // Matrix/scalar inversion
               _cimg_mp_op("Function 'inv()'");
               arg1 = compile(ss4,se1,depth1,0);
-              _cimg_mp_check_matrix_square(arg1,1);
-              p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
-              pos = vector(p1*p1);
-              CImg<ulongT>::vector((ulongT)mp_inv,pos,arg1,p1).move_to(code);
-              _cimg_mp_return(pos);
+              if (_cimg_mp_is_vector(arg1)) {
+                _cimg_mp_check_matrix_square(arg1,1);
+                p1 = (unsigned int)std::sqrt((float)_cimg_mp_vector_size(arg1));
+                pos = vector(p1*p1);
+                CImg<ulongT>::vector((ulongT)mp_matrix_inv,pos,arg1,p1).move_to(code);
+                _cimg_mp_return(pos);
+              }
+              if (_cimg_mp_is_constant(arg1)) _cimg_mp_constant(1/mem[arg1]);
+              _cimg_mp_scalar2(mp_div,1,arg1);
             }
 
             if (*ss1=='s') { // Family of 'is_?()' functions
@@ -17485,7 +17665,7 @@ namespace cimg_library_suffixed {
                 cimg::strellipsize(s0,64);
                 throw CImgArgumentException("[_cimg_math_parser] "
                                             "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
-                                            "do not match for third argument 'nb_colsB=%u', "
+                                            "do not match with third argument 'nb_colsB=%u', "
                                             "in expression '%s%s%s'.",
                                             pixel_type(),_cimg_mp_calling_function,s_op,
                                             s_type(arg1)._data,s_type(arg2)._data,p3,
@@ -17511,8 +17691,16 @@ namespace cimg_library_suffixed {
             }
 
             if ((cimg_sscanf(ss,"norm%u%c",&(arg1=~0U),&sep)==2 && sep=='(') ||
-                !std::strncmp(ss,"norminf(",8)) { // Lp norm
+                !std::strncmp(ss,"norminf(",8) || !std::strncmp(ss,"norm(",5) ||
+                (!std::strncmp(ss,"norm",4) && ss5<se1 && (s=std::strchr(ss5,'('))!=0)) { // Lp norm
               _cimg_mp_op("Function 'normP()'");
+              if (*ss4=='(') { arg1 = 2; s = ss5; }
+              else if (*ss4=='i' && *ss5=='n' && *ss6=='f' && *ss7=='(') { arg1 = ~0U; s = ss8; }
+              else if (arg1==~0U) {
+                arg1 = compile(ss4,s++,depth1,0);
+                _cimg_mp_check_constant(arg1,0,2);
+                arg1 = (unsigned int)mem[arg1];
+              } else s = std::strchr(ss4,'(') + 1;
               pos = scalar();
               switch (arg1) {
               case 0 :
@@ -17527,7 +17715,7 @@ namespace cimg_library_suffixed {
                 CImg<ulongT>::vector((ulongT)mp_normp,pos,0,(ulongT)(arg1==~0U?-1:(int)arg1)).
                   move_to(_opcode);
               }
-              for (s = std::strchr(ss5,'(') + 1; s<se; ++s) {
+              for ( ; s<se; ++s) {
                 ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
                                (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
                 arg2 = compile(s,ns,depth1,0);
@@ -17564,6 +17752,33 @@ namespace cimg_library_suffixed {
               _cimg_mp_scalar3(mp_permutations,arg1,arg2,arg3);
             }
 
+            if (!std::strncmp(ss,"pseudoinv(",10)) { // Matrix/scalar pseudo-inversion
+              _cimg_mp_op("Function 'pseudoinv()'");
+              s1 = ss + 10; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
+              arg1 = compile(ss + 10,s1,depth1,0);
+              arg2 = s1<se1?compile(++s1,se1,depth1,0):1;
+              _cimg_mp_check_type(arg1,1,2,0);
+              _cimg_mp_check_constant(arg2,2,3);
+              p1 = _cimg_mp_vector_size(arg1);
+              p2 = (unsigned int)mem[arg2];
+              p3 = p1/p2;
+              if (p3*p2!=p1) {
+                *se = saved_char;
+                s0 = ss - 4>expr._data?ss - 4:expr._data;
+                cimg::strellipsize(s0,64);
+                throw CImgArgumentException("[_cimg_math_parser] "
+                                            "CImg<%s>::%s: %s: Type of first argument ('%s') "
+                                            "does not match with second argument 'nb_colsA=%u', "
+                                            "in expression '%s%s%s'.",
+                                            pixel_type(),_cimg_mp_calling_function,s_op,
+                                            s_type(arg1)._data,p2,
+                                            s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
+              }
+              pos = vector(p1);
+              CImg<ulongT>::vector((ulongT)mp_matrix_pseudoinv,pos,arg1,p2,p3).move_to(code);
+              _cimg_mp_return(pos);
+            }
+
             if (!std::strncmp(ss,"print(",6)) { // Print expressions
               _cimg_mp_op("Function 'print()'");
               for (s = ss6; s<se; ++s) {
@@ -17778,7 +17993,7 @@ namespace cimg_library_suffixed {
                 cimg::strellipsize(s0,64);
                 throw CImgArgumentException("[_cimg_math_parser] "
                                             "CImg<%s>::%s: %s: Types of first and second arguments ('%s' and '%s') "
-                                            "do not match for third argument 'nb_colsB=%u', "
+                                            "do not match with third argument 'nb_colsB=%u', "
                                             "in expression '%s%s%s'.",
                                             pixel_type(),_cimg_mp_calling_function,s_op,
                                             s_type(arg1)._data,s_type(arg2)._data,p3,
@@ -17845,6 +18060,33 @@ namespace cimg_library_suffixed {
               p1 = _cimg_mp_vector_size(arg1);
               _cimg_mp_scalar3(mp_stod,arg1,p1,arg2);
             }
+
+            if (!std::strncmp(ss,"svd(",4)) { // Matrix SVD
+              _cimg_mp_op("Function 'svd()'");
+              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
+              arg1 = compile(ss4,s1,depth1,0);
+              arg2 = s1<se1?compile(++s1,se1,depth1,0):1;
+              _cimg_mp_check_type(arg1,1,2,0);
+              _cimg_mp_check_constant(arg2,2,3);
+              p1 = _cimg_mp_vector_size(arg1);
+              p2 = (unsigned int)mem[arg2];
+              p3 = p1/p2;
+              if (p3*p2!=p1) {
+                *se = saved_char;
+                s0 = ss - 4>expr._data?ss - 4:expr._data;
+                cimg::strellipsize(s0,64);
+                throw CImgArgumentException("[_cimg_math_parser] "
+                                            "CImg<%s>::%s: %s: Type of first argument ('%s') "
+                                            "does not match with second argument 'nb_colsA=%u', "
+                                            "in expression '%s%s%s'.",
+                                            pixel_type(),_cimg_mp_calling_function,s_op,
+                                            s_type(arg1)._data,p2,
+                                            s0!=expr._data?"...":"",s0,se<&expr.back()?"...":"");
+              }
+              pos = vector(p1 + p2 + p2*p2);
+              CImg<ulongT>::vector((ulongT)mp_matrix_svd,pos,arg1,p2,p3).move_to(code);
+              _cimg_mp_return(pos);
+            }
             break;
 
           case 't' :
@@ -17980,10 +18222,16 @@ namespace cimg_library_suffixed {
 
           case 'v' :
             if ((cimg_sscanf(ss,"vector%u%c",&(arg1=~0U),&sep)==2 && sep=='(' && arg1>0) ||
-                !std::strncmp(ss,"vector(",7)) { // Vector
+                !std::strncmp(ss,"vector(",7) ||
+                (!std::strncmp(ss,"vector",6) && ss7<se1 && (s=std::strchr(ss7,'('))!=0)) { // Vector
               _cimg_mp_op("Function 'vector()'");
               arg2 = 0; // Number of specified values.
-              s = std::strchr(ss6,'(') + 1;
+              if (arg1==~0U && *ss6!='(') {
+                arg1 = compile(ss6,s++,depth1,0);
+                _cimg_mp_check_constant(arg1,0,3);
+                arg1 = (unsigned int)mem[arg1];
+              } else s = std::strchr(ss6,'(') + 1;
+
               if (s<se1 || arg1==~0U) for ( ; s<se; ++s) {
                   ns = s; while (ns<se && (*ns!=',' || level[ns - expr._data]!=clevel1) &&
                                  (*ns!=')' || level[ns - expr._data]!=clevel)) ++ns;
@@ -18009,7 +18257,6 @@ namespace cimg_library_suffixed {
           case 'w' :
             if (!std::strncmp(ss,"whiledo",7) && (*ss7=='(' || (*ss7 && *ss7<=' ' && *ss8=='('))) { // While...do
               _cimg_mp_op("Function 'whiledo()'");
-              if (*ss7<=' ') cimg::swap(*ss7,*ss8); // Allow space before opening brace
               s1 = ss8; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
               p1 = code._width;
               arg1 = compile(ss8,s1,depth1,0);
@@ -18024,6 +18271,23 @@ namespace cimg_library_suffixed {
               _cimg_mp_return(pos);
             }
             break;
+
+          case 'x' :
+            if (!std::strncmp(ss,"xor(",4)) { // Xor
+              _cimg_mp_op("Function 'xor()'");
+              s1 = ss4; while (s1<se1 && (*s1!=',' || level[s1 - expr._data]!=clevel1)) ++s1;
+              arg1 = compile(ss4,s1,depth1,0);
+              arg2 = compile(++s1,se1,depth1,0);
+              _cimg_mp_check_type(arg2,2,3,_cimg_mp_vector_size(arg1));
+              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_xor,arg1,arg2);
+              if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_xor,arg1,arg2);
+              if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_xor,arg1,arg2);
+              if (_cimg_mp_is_constant(arg1) && _cimg_mp_is_constant(arg2))
+                _cimg_mp_constant((ulongT)mem[arg1] ^ (ulongT)mem[arg2]);
+              _cimg_mp_scalar2(mp_bitwise_xor,arg1,arg2);
+            }
+            break;
+
           }
 
           if (!std::strncmp(ss,"min(",4) || !std::strncmp(ss,"max(",4) ||
@@ -18447,16 +18711,64 @@ namespace cimg_library_suffixed {
 
       // Insert constant value in memory.
       unsigned int constant(const double val) {
+
+        // Search for built-in constant.
         if (val==(double)(int)val) {
           if (val>=0 && val<=10) return (unsigned int)val;
           if (val<0 && val>=-5) return (unsigned int)(10 - val);
         }
         if (val==0.5) return 16;
         if (cimg::type<double>::is_nan(val)) return _cimg_mp_slot_nan;
+
+        // Search for constant already requested before (in const cache).
+        unsigned int ind = ~0U;
+        if (constcache_size<1024) {
+          if (!constcache_size) {
+            constcache_vals.assign(16,1,1,1,0);
+            constcache_inds.assign(16,1,1,1,0);
+            *constcache_vals = val;
+            constcache_size = 1;
+            ind = 0;
+          } else { // Dichotomic search
+            const double val_beg = *constcache_vals, val_end = constcache_vals[constcache_size - 1];
+            if (val_beg>=val) ind = 0;
+            else if (val_end==val) ind = constcache_size - 1;
+            else if (val_end<val) ind = constcache_size;
+            else {
+              unsigned int i0 = 1, i1 = constcache_size - 2;
+              while (i0<=i1) {
+                const unsigned int mid = (i0 + i1)/2;
+                if (constcache_vals[mid]==val) { i0 = mid; break; }
+                else if (constcache_vals[mid]<val) i0 = mid + 1;
+                else i1 = mid - 1;
+              }
+              ind = i0;
+            }
+
+            if (ind>=constcache_size || constcache_vals[ind]!=val) {
+              ++constcache_size;
+              if (constcache_size>constcache_vals._width) {
+                constcache_vals.resize(-200,1,1,1,0);
+                constcache_inds.resize(-200,1,1,1,0);
+              }
+              const int l = constcache_size - (int)ind - 1;
+              if (l>0) {
+                std::memmove(&constcache_vals[ind + 1],&constcache_vals[ind],l*sizeof(double));
+                std::memmove(&constcache_inds[ind + 1],&constcache_inds[ind],l*sizeof(unsigned int));
+              }
+              constcache_vals[ind] = val;
+              constcache_inds[ind] = 0;
+            }
+          }
+          if (constcache_inds[ind]) return constcache_inds[ind];
+        }
+
+        // Insert new constant in memory if necessary.
         if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); }
         const unsigned int pos = mempos++;
         mem[pos] = val;
         memtype[pos] = 1; // Set constant property
+        if (ind!=~0U) constcache_inds[ind] = pos;
         return pos;
       }
 
@@ -18574,7 +18886,7 @@ namespace cimg_library_suffixed {
       }
 
       // Insert code instructions for processing vectors.
-      bool is_tmp_vector(const unsigned int arg) const {
+      bool is_comp_vector(const unsigned int arg) const {
         unsigned int siz = _cimg_mp_vector_size(arg);
         if (siz>8) return false;
         const int *ptr = memtype.data(arg + 1);
@@ -18639,7 +18951,7 @@ namespace cimg_library_suffixed {
       unsigned int vector1_v(const mp_func op, const unsigned int arg1) {
         const unsigned int
           siz = _cimg_mp_vector_size(arg1),
-          pos = is_tmp_vector(arg1)?arg1:vector(siz);
+          pos = is_comp_vector(arg1)?arg1:vector(siz);
         if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_v,pos,siz,(ulongT)op,arg1).move_to(code);
         else {
           code.insert(siz);
@@ -18652,7 +18964,7 @@ namespace cimg_library_suffixed {
       unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
         const unsigned int
           siz = _cimg_mp_vector_size(arg1),
-          pos = is_tmp_vector(arg1)?arg1:is_tmp_vector(arg2)?arg2:vector(siz);
+          pos = is_comp_vector(arg1)?arg1:is_comp_vector(arg2)?arg2:vector(siz);
         if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
         else {
           code.insert(siz);
@@ -18665,7 +18977,7 @@ namespace cimg_library_suffixed {
       unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
         const unsigned int
           siz = _cimg_mp_vector_size(arg1),
-          pos = is_tmp_vector(arg1)?arg1:vector(siz);
+          pos = is_comp_vector(arg1)?arg1:vector(siz);
         if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vs,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
         else {
           code.insert(siz);
@@ -18678,7 +18990,7 @@ namespace cimg_library_suffixed {
       unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) {
         const unsigned int
           siz = _cimg_mp_vector_size(arg2),
-          pos = is_tmp_vector(arg2)?arg2:vector(siz);
+          pos = is_comp_vector(arg2)?arg2:vector(siz);
         if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_sv,pos,siz,(ulongT)op,arg1,arg2).move_to(code);
         else {
           code.insert(siz);
@@ -18692,7 +19004,7 @@ namespace cimg_library_suffixed {
                                const unsigned int arg3) {
         const unsigned int
           siz = _cimg_mp_vector_size(arg1),
-          pos = is_tmp_vector(arg1)?arg1:vector(siz);
+          pos = is_comp_vector(arg1)?arg1:vector(siz);
         if (siz>24) CImg<ulongT>::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code);
         else {
           code.insert(siz);
@@ -18924,12 +19236,22 @@ namespace cimg_library_suffixed {
         return (double)((longT)_mp_arg(2)>>(unsigned int)_mp_arg(3));
       }
 
+      static double mp_bitwise_xor(_cimg_math_parser& mp) {
+        return (double)((ulongT)_mp_arg(2) ^ (ulongT)_mp_arg(3));
+      }
+
       static double mp_break(_cimg_math_parser& mp) {
         mp.break_type = 1;
         mp.p_code = mp.p_break - 1;
         return cimg::type<double>::nan();
       }
 
+      static double mp_breakpoint(_cimg_math_parser& mp) {
+        cimg_abort_test();
+        cimg::unused(mp);
+        return cimg::type<double>::nan();
+      }
+
       static double mp_cbrt(_cimg_math_parser& mp) {
         return cimg::cbrt(_mp_arg(2));
       }
@@ -19303,17 +19625,6 @@ namespace cimg_library_suffixed {
         return cimg::type<double>::nan();
       }
 
-      static double mp_eig(_cimg_math_parser& mp) {
-        double *ptrd = &_mp_arg(1) + 1;
-        const double *ptr1 = &_mp_arg(2) + 1;
-        const unsigned int k = (unsigned int)mp.opcode[3];
-        CImg<double> val, vec;
-        CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
-        CImg<double>(ptrd,k,1,1,1,true) = val.unroll('x');
-        CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
-        return cimg::type<double>::nan();
-      }
-
       static double mp_eq(_cimg_math_parser& mp) {
         return (double)(_mp_arg(2)==_mp_arg(3));
       }
@@ -19515,14 +19826,6 @@ namespace cimg_library_suffixed {
         return (double)(longT)_mp_arg(2);
       }
 
-      static double mp_inv(_cimg_math_parser& mp) {
-        double *ptrd = &_mp_arg(1) + 1;
-        const double *ptr1 = &_mp_arg(2) + 1;
-        const unsigned int k = (unsigned int)mp.opcode[3];
-        CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();
-        return cimg::type<double>::nan();
-      }
-
       static double mp_ioff(_cimg_math_parser& mp) {
         const unsigned int
           boundary_conditions = (unsigned int)_mp_arg(3);
@@ -20291,6 +20594,25 @@ namespace cimg_library_suffixed {
         return (double)(_mp_arg(2)<=_mp_arg(3));
       }
 
+      static double mp_matrix_eig(_cimg_math_parser& mp) {
+        double *ptrd = &_mp_arg(1) + 1;
+        const double *ptr1 = &_mp_arg(2) + 1;
+        const unsigned int k = (unsigned int)mp.opcode[3];
+        CImg<double> val, vec;
+        CImg<double>(ptr1,k,k,1,1,true).symmetric_eigen(val,vec);
+        CImg<double>(ptrd,1,k,1,1,true) = val;
+        CImg<double>(ptrd + k,k,k,1,1,true) = vec.get_transpose();
+        return cimg::type<double>::nan();
+      }
+
+      static double mp_matrix_inv(_cimg_math_parser& mp) {
+        double *ptrd = &_mp_arg(1) + 1;
+        const double *ptr1 = &_mp_arg(2) + 1;
+        const unsigned int k = (unsigned int)mp.opcode[3];
+        CImg<double>(ptrd,k,k,1,1,true) = CImg<double>(ptr1,k,k,1,1,true).get_invert();
+        return cimg::type<double>::nan();
+      }
+
       static double mp_matrix_mul(_cimg_math_parser& mp) {
         double *ptrd = &_mp_arg(1) + 1;
         const double
@@ -20304,6 +20626,30 @@ namespace cimg_library_suffixed {
         return cimg::type<double>::nan();
       }
 
+      static double mp_matrix_pseudoinv(_cimg_math_parser& mp) {
+        double *ptrd = &_mp_arg(1) + 1;
+        const double *ptr1 = &_mp_arg(2) + 1;
+        const unsigned int
+          k = (unsigned int)mp.opcode[3],
+          l = (unsigned int)mp.opcode[4];
+        CImg<double>(ptrd,l,k,1,1,true) = CImg<double>(ptr1,k,l,1,1,true).get_pseudoinvert();
+        return cimg::type<double>::nan();
+      }
+
+      static double mp_matrix_svd(_cimg_math_parser& mp) {
+        double *ptrd = &_mp_arg(1) + 1;
+        const double *ptr1 = &_mp_arg(2) + 1;
+        const unsigned int
+          k = (unsigned int)mp.opcode[3],
+          l = (unsigned int)mp.opcode[4];
+        CImg<double> U, S, V;
+        CImg<double>(ptr1,k,l,1,1,true).SVD(U,S,V);
+        CImg<double>(ptrd,k,l,1,1,true) = U;
+        CImg<double>(ptrd + k*l,1,k,1,1,true) = S;
+        CImg<double>(ptrd + k*l + k,k,k,1,1,true) = V;
+        return cimg::type<double>::nan();
+      }
+
       static double mp_max(_cimg_math_parser& mp) {
         const unsigned int i_end = (unsigned int)mp.opcode[2];
         double val = _mp_arg(3);
@@ -20985,7 +21331,7 @@ namespace cimg_library_suffixed {
       static double mp_sum(_cimg_math_parser& mp) {
         const unsigned int i_end = (unsigned int)mp.opcode[2];
         double val = _mp_arg(3);
-        for (unsigned int i = 3; i<i_end; ++i) val+=_mp_arg(i);
+        for (unsigned int i = 4; i<i_end; ++i) val+=_mp_arg(i);
         return val;
       }
 
@@ -21225,7 +21571,15 @@ namespace cimg_library_suffixed {
             siz = siz0;
           cimg::mutex(6);
           std::fprintf(cimg::output(),"\n[_cimg_math_parser] %s = [ ",expr._data);
-          while (siz-->0) std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":"");
+          unsigned int count = 0;
+          while (siz-->0) {
+            if (count>=64 && siz>=64) {
+              std::fprintf(cimg::output(),"...,");
+              ptr = (unsigned int)mp.opcode[1] + 1 + siz0 - 64;
+              siz = 64;
+            } else std::fprintf(cimg::output(),"%g%s",mp.mem[ptr++],siz?",":"");
+            ++count;
+          }
           std::fprintf(cimg::output()," ] (size: %u)",siz0);
           std::fflush(cimg::output());
           cimg::mutex(6,0);
@@ -25026,6 +25380,7 @@ namespace cimg_library_suffixed {
         if (repeat_values && nb && nb<siz)
           for (T *ptrs = _data, *const ptre = _data + siz; ptrd<ptre; ++ptrs) *(ptrd++) = *ptrs;
       }
+
       cimg::exception_mode(omode);
       cimg_abort_test();
       return *this;
@@ -26220,7 +26575,7 @@ namespace cimg_library_suffixed {
           dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1;
         }
       }
-      return _get_label(nb,dx,dy,dz,tolerance);
+      return _label(nb,dx,dy,dz,tolerance);
     }
 
     //! Label connected components \overloading.
@@ -26245,12 +26600,12 @@ namespace cimg_library_suffixed {
                                                connectivity_mask(x,y,z)) {
         dx[nb] = x; dy[nb] = y; dz[nb++] = z;
       }
-      return _get_label(nb,dx,dy,dz,tolerance);
+      return _label(nb,dx,dy,dz,tolerance);
     }
 
-    CImg<ulongT> _get_label(const unsigned int nb, const int
-                            *const dx, const int *const dy, const int *const dz,
-                            const Tfloat tolerance) const {
+    CImg<ulongT> _label(const unsigned int nb, const int
+                        *const dx, const int *const dy, const int *const dz,
+                        const Tfloat tolerance) const {
       CImg<ulongT> res(_width,_height,_depth,_spectrum);
       cimg_forC(*this,c) {
         CImg<ulongT> _res = res.get_shared_channel(c);
@@ -27018,9 +27373,9 @@ namespace cimg_library_suffixed {
 
     //! Convert pixel values from RGB to XYZ color spaces.
     /**
-       \note Use formula from the Wikipedia page : https://en.wikipedia.org/wiki/CIE_1931_color_space
+       \param use_D65 Tell to use the D65 illuminant (D50 otherwise).
     **/
-    CImg<T>& RGBtoXYZ() {
+    CImg<T>& RGBtoXYZ(const bool use_D65=true) {
       if (_spectrum!=3)
         throw CImgInstanceException(_cimg_instance
                                     "RGBtoXYZ(): Instance is not a RGB image.",
@@ -27034,20 +27389,29 @@ namespace cimg_library_suffixed {
           R = (Tfloat)p1[N]/255,
           G = (Tfloat)p2[N]/255,
           B = (Tfloat)p3[N]/255;
-        p1[N] = (T)(0.43603516*R + 0.38511658*G + 0.14305115*B);
-        p2[N] = (T)(0.22248840*R + 0.71690369*G + 0.06060791*B);
-        p3[N] = (T)(0.01391602*R + 0.09706116*G + 0.71392822*B);
+        if (use_D65) { // D65
+          p1[N] = (T)(0.4124564*R + 0.3575761*G + 0.1804375*B);
+          p2[N] = (T)(0.2126729*R + 0.7151522*G + 0.0721750*B);
+          p3[N] = (T)(0.0193339*R + 0.1191920*G + 0.9503041*B);
+        } else { // D50
+          p1[N] = (T)(0.43603516*R + 0.38511658*G + 0.14305115*B);
+          p2[N] = (T)(0.22248840*R + 0.71690369*G + 0.06060791*B);
+          p3[N] = (T)(0.01391602*R + 0.09706116*G + 0.71392822*B);
+        }
       }
       return *this;
     }
 
     //! Convert pixel values from RGB to XYZ color spaces \newinstance.
-    CImg<Tfloat> get_RGBtoXYZ() const {
-      return CImg<Tfloat>(*this,false).RGBtoXYZ();
+    CImg<Tfloat> get_RGBtoXYZ(const bool use_D65=true) const {
+      return CImg<Tfloat>(*this,false).RGBtoXYZ(use_D65);
     }
 
     //! Convert pixel values from XYZ to RGB color spaces.
-    CImg<T>& XYZtoRGB() {
+    /**
+       \param use_D65 Tell to use the D65 illuminant (D50 otherwise).
+    **/
+    CImg<T>& XYZtoRGB(const bool use_D65=true) {
       if (_spectrum!=3)
         throw CImgInstanceException(_cimg_instance
                                     "XYZtoRGB(): Instance is not a XYZ image.",
@@ -27061,27 +27425,33 @@ namespace cimg_library_suffixed {
           X = (Tfloat)p1[N]*255,
           Y = (Tfloat)p2[N]*255,
           Z = (Tfloat)p3[N]*255;
-        p1[N] = (T)cimg::cut(3.134274799724*X  - 1.617275708956*Y - 0.490724283042*Z,0,255);
-        p2[N] = (T)cimg::cut(-0.978795575994*X + 1.916161689117*Y + 0.033453331711*Z,0,255);
-        p3[N] = (T)cimg::cut(0.071976988401*X - 0.228984974402*Y + 1.405718224383*Z,0,255);
+        if (use_D65) {
+          p1[N] = (T)cimg::cut(3.2404542*X - 1.5371385*Y - 0.4985314*Z,0,255);
+          p2[N] = (T)cimg::cut(-0.9692660*X + 1.8760108*Y + 0.0415560*Z,0,255);
+          p3[N] = (T)cimg::cut(0.0556434*X - 0.2040259*Y + 1.0572252*Z,0,255);
+        } else {
+          p1[N] = (T)cimg::cut(3.134274799724*X  - 1.617275708956*Y - 0.490724283042*Z,0,255);
+          p2[N] = (T)cimg::cut(-0.978795575994*X + 1.916161689117*Y + 0.033453331711*Z,0,255);
+          p3[N] = (T)cimg::cut(0.071976988401*X - 0.228984974402*Y + 1.405718224383*Z,0,255);
+        }
       }
       return *this;
     }
 
     //! Convert pixel values from XYZ to RGB color spaces \newinstance.
-    CImg<Tuchar> get_XYZtoRGB() const {
-      return CImg<Tuchar>(*this,false).XYZtoRGB();
+    CImg<Tuchar> get_XYZtoRGB(const bool use_D65=true) const {
+      return CImg<Tuchar>(*this,false).XYZtoRGB(use_D65);
     }
 
     //! Convert pixel values from XYZ to Lab color spaces.
-    CImg<T>& XYZtoLab() {
+    CImg<T>& XYZtoLab(const bool use_D65=true) {
 #define _cimg_Labf(x) (24389*(x)>216?cimg::cbrt(x):(24389*(x)/27 + 16)/116)
 
       if (_spectrum!=3)
         throw CImgInstanceException(_cimg_instance
                                     "XYZtoLab(): Instance is not a XYZ image.",
                                     cimg_instance);
-      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ();
+      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ(use_D65);
       T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
       const ulongT whd = (ulongT)_width*_height*_depth;
       cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=128))
@@ -27101,17 +27471,17 @@ namespace cimg_library_suffixed {
     }
 
     //! Convert pixel values from XYZ to Lab color spaces \newinstance.
-    CImg<Tfloat> get_XYZtoLab() const {
-      return CImg<Tfloat>(*this,false).XYZtoLab();
+    CImg<Tfloat> get_XYZtoLab(const bool use_D65=true) const {
+      return CImg<Tfloat>(*this,false).XYZtoLab(use_D65);
     }
 
     //! Convert pixel values from Lab to XYZ color spaces.
-    CImg<T>& LabtoXYZ() {
+    CImg<T>& LabtoXYZ(const bool use_D65=true) {
       if (_spectrum!=3)
         throw CImgInstanceException(_cimg_instance
                                     "LabtoXYZ(): Instance is not a Lab image.",
                                     cimg_instance);
-      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ();
+      const CImg<Tfloat> white = CImg<Tfloat>(1,1,1,3,255).RGBtoXYZ(use_D65);
       T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2);
       const ulongT whd = (ulongT)_width*_height*_depth;
       cimg_pragma_openmp(parallel for cimg_openmp_if(whd>=128))
@@ -27134,8 +27504,8 @@ namespace cimg_library_suffixed {
     }
 
     //! Convert pixel values from Lab to XYZ color spaces \newinstance.
-    CImg<Tfloat> get_LabtoXYZ() const {
-      return CImg<Tfloat>(*this,false).LabtoXYZ();
+    CImg<Tfloat> get_LabtoXYZ(const bool use_D65=true) const {
+      return CImg<Tfloat>(*this,false).LabtoXYZ(use_D65);
     }
 
     //! Convert pixel values from XYZ to xyY color spaces.
@@ -27196,43 +27566,43 @@ namespace cimg_library_suffixed {
     }
 
     //! Convert pixel values from RGB to Lab color spaces.
-    CImg<T>& RGBtoLab() {
-      return RGBtoXYZ().XYZtoLab();
+    CImg<T>& RGBtoLab(const bool use_D65=true) {
+      return RGBtoXYZ(use_D65).XYZtoLab(use_D65);
     }
 
     //! Convert pixel values from RGB to Lab color spaces \newinstance.
-    CImg<Tfloat> get_RGBtoLab() const {
-      return CImg<Tfloat>(*this,false).RGBtoLab();
+    CImg<Tfloat> get_RGBtoLab(const bool use_D65=true) const {
+      return CImg<Tfloat>(*this,false).RGBtoLab(use_D65);
     }
 
     //! Convert pixel values from Lab to RGB color spaces.
-    CImg<T>& LabtoRGB() {
-      return LabtoXYZ().XYZtoRGB();
+    CImg<T>& LabtoRGB(const bool use_D65=true) {
+      return LabtoXYZ().XYZtoRGB(use_D65);
     }
 
     //! Convert pixel values from Lab to RGB color spaces \newinstance.
-    CImg<Tuchar> get_LabtoRGB() const {
-      return CImg<Tuchar>(*this,false).LabtoRGB();
+    CImg<Tuchar> get_LabtoRGB(const bool use_D65=true) const {
+      return CImg<Tuchar>(*this,false).LabtoRGB(use_D65);
     }
 
     //! Convert pixel values from RGB to xyY color spaces.
-    CImg<T>& RGBtoxyY() {
-      return RGBtoXYZ().XYZtoxyY();
+    CImg<T>& RGBtoxyY(const bool use_D65=true) {
+      return RGBtoXYZ(use_D65).XYZtoxyY();
     }
 
     //! Convert pixel values from RGB to xyY color spaces \newinstance.
-    CImg<Tfloat> get_RGBtoxyY() const {
-      return CImg<Tfloat>(*this,false).RGBtoxyY();
+    CImg<Tfloat> get_RGBtoxyY(const bool use_D65=true) const {
+      return CImg<Tfloat>(*this,false).RGBtoxyY(use_D65);
     }
 
     //! Convert pixel values from xyY to RGB color spaces.
-    CImg<T>& xyYtoRGB() {
-      return xyYtoXYZ().XYZtoRGB();
+    CImg<T>& xyYtoRGB(const bool use_D65=true) {
+      return xyYtoXYZ().XYZtoRGB(use_D65);
     }
 
     //! Convert pixel values from xyY to RGB color spaces \newinstance.
-    CImg<Tuchar> get_xyYtoRGB() const {
-      return CImg<Tuchar>(*this,false).xyYtoRGB();
+    CImg<Tuchar> get_xyYtoRGB(const bool use_D65=true) const {
+      return CImg<Tuchar>(*this,false).xyYtoRGB(use_D65);
     }
 
     //! Convert pixel values from RGB to CMYK color spaces.
@@ -27574,37 +27944,37 @@ namespace cimg_library_suffixed {
         //
       case 3 : {
         CImg<uintT> off(cimg::max(sx,sy,sz,sc));
-        CImg<floatT> foff(off._width);
+        CImg<doubleT> foff(off._width);
         CImg<T> resx, resy, resz, resc;
+        double curr, old;
 
         if (sx!=_width) {
           if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
+          else if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
           else {
-            if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
-            else {
-              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;
-              resx.assign(sx,_height,_depth,_spectrum);
-              float curr = 0, old = 0;
-              unsigned int *poff = off._data;
-              float *pfoff = foff._data;
-              cimg_forX(resx,x) {
-                *(pfoff++) = curr - (unsigned int)curr;
-                old = curr;
-                curr+=fx;
-                *(poff++) = (unsigned int)curr - (unsigned int)old;
-              }
-              cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resx.size()>=65536))
+            const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0)/(sx - 1):0):
+              (double)_width/sx;
+            resx.assign(sx,_height,_depth,_spectrum);
+            curr = old = 0;
+            unsigned int *poff = off._data;
+            double *pfoff = foff._data;
+            cimg_forX(resx,x) {
+              *(pfoff++) = curr - (unsigned int)curr;
+              old = curr;
+              curr = std::min(width() - 1.0,curr + fx);
+              *(poff++) = (unsigned int)curr - (unsigned int)old;
+            }
+            cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resx.size()>=65536))
               cimg_forYZC(resx,y,z,c) {
-                const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1;
-                T *ptrd = resx.data(0,y,z,c);
-                const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
-                cimg_forX(resx,x) {
-                  const float alpha = *(pfoff++);
-                  const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + 1):val1;
-                  *(ptrd++) = (T)((1 - alpha)*val1 + alpha*val2);
-                  ptrs+=*(poff++);
-                }
+              const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1;
+              T *ptrd = resx.data(0,y,z,c);
+              const unsigned int *poff = off._data;
+              const double *pfoff = foff._data;
+              cimg_forX(resx,x) {
+                const double alpha = *(pfoff++);
+                const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + 1):val1;
+                *(ptrd++) = (T)((1 - alpha)*val1 + alpha*val2);
+                ptrs+=*(poff++);
               }
             }
           }
@@ -27615,16 +27985,16 @@ namespace cimg_library_suffixed {
           else {
             if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
             else {
-              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):
-                (float)_height/sy;
+              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0)/(sy - 1):0):
+                (double)_height/sy;
               resy.assign(sx,sy,_depth,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forY(resy,y) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fy;
+                curr = std::min(height() - 1.0,curr + fy);
                 *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resy.size()>=65536))
@@ -27632,9 +28002,9 @@ namespace cimg_library_suffixed {
                 const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx;
                 T *ptrd = resy.data(x,0,z,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forY(resy,y) {
-                  const float alpha = *(pfoff++);
+                  const double alpha = *(pfoff++);
                   const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sx):val1;
                   *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                   ptrd+=sx;
@@ -27651,16 +28021,17 @@ namespace cimg_library_suffixed {
           else {
             if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
             else {
-              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;
+              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0)/(sz - 1):0):
+                (double)_depth/sz;
               const unsigned int sxy = sx*sy;
               resz.assign(sx,sy,sz,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forZ(resz,z) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fz;
+                curr = std::min(depth() - 1.0,curr + fz);
                 *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resz.size()>=65536))
@@ -27668,9 +28039,9 @@ namespace cimg_library_suffixed {
                 const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy;
                 T *ptrd = resz.data(x,y,0,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forZ(resz,z) {
-                  const float alpha = *(pfoff++);
+                  const double alpha = *(pfoff++);
                   const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxy):val1;
                   *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                   ptrd+=sxy;
@@ -27687,17 +28058,17 @@ namespace cimg_library_suffixed {
           else {
             if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
             else {
-              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):
-                (float)_spectrum/sc;
+              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0)/(sc - 1):0):
+                (double)_spectrum/sc;
               const unsigned int sxyz = sx*sy*sz;
               resc.assign(sx,sy,sz,sc);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forC(resc,c) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fc;
+                curr = std::min(spectrum() - 1.0,curr + fc);
                 *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resc.size()>=65536))
@@ -27705,9 +28076,9 @@ namespace cimg_library_suffixed {
                 const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz;
                 T *ptrd = resc.data(x,y,z,0);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forC(resc,c) {
-                  const float alpha = *(pfoff++);
+                  const double alpha = *(pfoff++);
                   const T val1 = *ptrs, val2 = ptrs<ptrsmax?*(ptrs + sxyz):val1;
                   *ptrd = (T)((1 - alpha)*val1 + alpha*val2);
                   ptrd+=sxyz;
@@ -27792,23 +28163,25 @@ namespace cimg_library_suffixed {
       case 5 : {
         const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();
         CImg<uintT> off(cimg::max(sx,sy,sz,sc));
-        CImg<floatT> foff(off._width);
+        CImg<doubleT> foff(off._width);
         CImg<T> resx, resy, resz, resc;
+        double curr, old;
 
         if (sx!=_width) {
           if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
           else {
             if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
             else {
-              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;
+              const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0)/(sx - 1):0):
+                (double)_width/sx;
               resx.assign(sx,_height,_depth,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forX(resx,x) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fx;
+                curr = std::min(width() - 1.0,curr + fx);
                 *(poff++) = (unsigned int)curr - (unsigned int)old;
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resx.size()>=65536))
@@ -27816,14 +28189,14 @@ namespace cimg_library_suffixed {
                 const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2);
                 T *ptrd = resx.data(0,y,z,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forX(resx,x) {
-                  const float t = *(pfoff++);
-                  const Tfloat
-                    val1 = (Tfloat)*ptrs,
-                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - 1):val1,
-                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val1,
-                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2):val2,
+                  const double
+                    t = *(pfoff++),
+                    val1 = (double)*ptrs,
+                    val0 = ptrs>ptrs0?(double)*(ptrs - 1):val1,
+                    val2 = ptrs<=ptrsmax?(double)*(ptrs + 1):val1,
+                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2):val2,
                     val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                        t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                   *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);
@@ -27839,16 +28212,16 @@ namespace cimg_library_suffixed {
           else {
             if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
             else {
-              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):
-                (float)_height/sy;
+              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0)/(sy - 1):0):
+                (double)_height/sy;
               resy.assign(sx,sy,_depth,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forY(resy,y) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fy;
+                curr = std::min(height() - 1.0,curr + fy);
                 *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resy.size()>=65536))
@@ -27856,14 +28229,14 @@ namespace cimg_library_suffixed {
                 const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx;
                 T *ptrd = resy.data(x,0,z,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forY(resy,y) {
-                  const float t = *(pfoff++);
-                  const Tfloat
-                    val1 = (Tfloat)*ptrs,
-                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sx):val1,
-                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val1,
-                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sx):val2,
+                  const double
+                    t = *(pfoff++),
+                    val1 = (double)*ptrs,
+                    val0 = ptrs>ptrs0?(double)*(ptrs - sx):val1,
+                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sx):val1,
+                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sx):val2,
                     val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                        t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
@@ -27881,16 +28254,17 @@ namespace cimg_library_suffixed {
           else {
             if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
             else {
-              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;
+              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0)/(sz - 1):0):
+                (double)_depth/sz;
               const unsigned int sxy = sx*sy;
               resz.assign(sx,sy,sz,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forZ(resz,z) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fz;
+                curr = std::min(depth() - 1.0,curr + fz);
                 *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resz.size()>=65536))
@@ -27898,14 +28272,14 @@ namespace cimg_library_suffixed {
                 const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy;
                 T *ptrd = resz.data(x,y,0,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forZ(resz,z) {
-                  const float t = *(pfoff++);
-                  const Tfloat
-                    val1 = (Tfloat)*ptrs,
-                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxy):val1,
-                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val1,
-                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxy):val2,
+                  const double
+                    t = *(pfoff++),
+                    val1 = (double)*ptrs,
+                    val0 = ptrs>ptrs0?(double)*(ptrs - sxy):val1,
+                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val1,
+                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sxy):val2,
                     val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                        t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
@@ -27923,17 +28297,17 @@ namespace cimg_library_suffixed {
           else {
             if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
             else {
-              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):
-                (float)_spectrum/sc;
+              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0)/(sc - 1):0):
+                (double)_spectrum/sc;
               const unsigned int sxyz = sx*sy*sz;
               resc.assign(sx,sy,sz,sc);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forC(resc,c) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fc;
+                curr = std::min(spectrum() - 1.0,curr + fc);
                 *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resc.size()>=65536))
@@ -27941,14 +28315,14 @@ namespace cimg_library_suffixed {
                 const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;
                 T *ptrd = resc.data(x,y,z,0);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forC(resc,c) {
-                  const float t = *(pfoff++);
-                  const Tfloat
-                    val1 = (Tfloat)*ptrs,
-                    val0 = ptrs>ptrs0?(Tfloat)*(ptrs - sxyz):val1,
-                    val2 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val1,
-                    val3 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxyz):val2,
+                  const double
+                    t = *(pfoff++),
+                    val1 = (double)*ptrs,
+                    val0 = ptrs>ptrs0?(double)*(ptrs - sxyz):val1,
+                    val2 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val1,
+                    val3 = ptrs<ptrsmax?(double)*(ptrs + 2*sxyz):val2,
                     val = val1 + 0.5f*(t*(-val0 + val2) + t*t*(2*val0 - 5*val1 + 4*val2 - val3) +
                                        t*t*t*(-val0 + 3*val1 - 3*val2 + val3));
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
@@ -27967,25 +28341,27 @@ namespace cimg_library_suffixed {
         // Lanczos interpolation.
         //
       case 6 : {
-        const Tfloat vmin = (Tfloat)cimg::type<T>::min(), vmax = (Tfloat)cimg::type<T>::max();
+        const double vmin = (double)cimg::type<T>::min(), vmax = (double)cimg::type<T>::max();
         CImg<uintT> off(cimg::max(sx,sy,sz,sc));
-        CImg<floatT> foff(off._width);
+        CImg<doubleT> foff(off._width);
         CImg<T> resx, resy, resz, resc;
+        double curr, old;
 
         if (sx!=_width) {
           if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx);
           else {
             if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx);
             else {
-              const float fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0f)/(sx - 1):0):(float)_width/sx;
+              const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.0)/(sx - 1):0):
+                (double)_width/sx;
               resx.assign(sx,_height,_depth,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forX(resx,x) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fx;
+                curr = std::min(width() - 1.0,curr + fx);
                 *(poff++) = (unsigned int)curr - (unsigned int)old;
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resx.size()>=65536))
@@ -27994,21 +28370,20 @@ namespace cimg_library_suffixed {
                   *const ptrsmax = ptrs0 + (_width - 2);
                 T *ptrd = resx.data(0,y,z,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forX(resx,x) {
-                  const float
+                  const double
                     t = *(pfoff++),
                     w0 = _cimg_lanczos(t + 2),
                     w1 = _cimg_lanczos(t + 1),
                     w2 = _cimg_lanczos(t),
                     w3 = _cimg_lanczos(t - 1),
-                    w4 = _cimg_lanczos(t - 2);
-                  const Tfloat
-                    val2 = (Tfloat)*ptrs,
-                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - 1):val2,
-                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2):val1,
-                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + 1):val2,
-                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2):val3,
+                    w4 = _cimg_lanczos(t - 2),
+                    val2 = (double)*ptrs,
+                    val1 = ptrs>=ptrsmin?(double)*(ptrs - 1):val2,
+                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2):val1,
+                    val3 = ptrs<=ptrsmax?(double)*(ptrs + 1):val2,
+                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2):val3,
                     val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                   *(ptrd++) = (T)(val<vmin?vmin:val>vmax?vmax:val);
                   ptrs+=*(poff++);
@@ -28023,16 +28398,16 @@ namespace cimg_library_suffixed {
           else {
             if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy);
             else {
-              const float fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0f)/(sy - 1):0):
-                (float)_height/sy;
+              const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.0)/(sy - 1):0):
+                (double)_height/sy;
               resy.assign(sx,sy,_depth,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forY(resy,y) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fy;
+                curr = std::min(height() - 1.0,curr + fy);
                 *(poff++) = sx*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resy.size()>=65536))
@@ -28041,21 +28416,20 @@ namespace cimg_library_suffixed {
                   *const ptrsmax = ptrs0 + (_height - 2)*sx;
                 T *ptrd = resy.data(x,0,z,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forY(resy,y) {
-                  const float
+                  const double
                     t = *(pfoff++),
                     w0 = _cimg_lanczos(t + 2),
                     w1 = _cimg_lanczos(t + 1),
                     w2 = _cimg_lanczos(t),
                     w3 = _cimg_lanczos(t - 1),
-                    w4 = _cimg_lanczos(t - 2);
-                  const Tfloat
-                    val2 = (Tfloat)*ptrs,
-                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sx):val2,
-                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sx):val1,
-                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sx):val2,
-                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sx):val3,
+                    w4 = _cimg_lanczos(t - 2),
+                    val2 = (double)*ptrs,
+                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sx):val2,
+                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sx):val1,
+                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sx):val2,
+                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sx):val3,
                     val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                   ptrd+=sx;
@@ -28072,16 +28446,17 @@ namespace cimg_library_suffixed {
           else {
             if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz);
             else {
-              const float fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0f)/(sz - 1):0):(float)_depth/sz;
+              const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.0)/(sz - 1):0):
+                (double)_depth/sz;
               const unsigned int sxy = sx*sy;
               resz.assign(sx,sy,sz,_spectrum);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forZ(resz,z) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fz;
+                curr = std::min(depth() - 1.0,curr + fz);
                 *(poff++) = sxy*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resz.size()>=65536))
@@ -28090,21 +28465,20 @@ namespace cimg_library_suffixed {
                   *const ptrsmax = ptrs0 + (_depth - 2)*sxy;
                 T *ptrd = resz.data(x,y,0,c);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forZ(resz,z) {
-                  const float
+                  const double
                     t = *(pfoff++),
                     w0 = _cimg_lanczos(t + 2),
                     w1 = _cimg_lanczos(t + 1),
                     w2 = _cimg_lanczos(t),
                     w3 = _cimg_lanczos(t - 1),
-                    w4 = _cimg_lanczos(t - 2);
-                  const Tfloat
-                    val2 = (Tfloat)*ptrs,
-                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxy):val2,
-                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxy):val1,
-                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxy):val2,
-                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxy):val3,
+                    w4 = _cimg_lanczos(t - 2),
+                    val2 = (double)*ptrs,
+                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sxy):val2,
+                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxy):val1,
+                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val2,
+                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sxy):val3,
                     val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                   ptrd+=sxy;
@@ -28121,17 +28495,17 @@ namespace cimg_library_suffixed {
           else {
             if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc);
             else {
-              const float fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0f)/(sc - 1):0):
-                (float)_spectrum/sc;
+              const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.0)/(sc - 1):0):
+                (double)_spectrum/sc;
               const unsigned int sxyz = sx*sy*sz;
               resc.assign(sx,sy,sz,sc);
-              float curr = 0, old = 0;
+              curr = old = 0;
               unsigned int *poff = off._data;
-              float *pfoff = foff._data;
+              double *pfoff = foff._data;
               cimg_forC(resc,c) {
                 *(pfoff++) = curr - (unsigned int)curr;
                 old = curr;
-                curr+=fc;
+                curr = std::min(spectrum() - 1.0,curr + fc);
                 *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old);
               }
               cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(resc.size()>=65536))
@@ -28140,21 +28514,20 @@ namespace cimg_library_suffixed {
                   *const ptrsmax = ptrs + (_spectrum - 2)*sxyz;
                 T *ptrd = resc.data(x,y,z,0);
                 const unsigned int *poff = off._data;
-                const float *pfoff = foff._data;
+                const double *pfoff = foff._data;
                 cimg_forC(resc,c) {
-                  const float
+                  const double
                     t = *(pfoff++),
                     w0 = _cimg_lanczos(t + 2),
                     w1 = _cimg_lanczos(t + 1),
                     w2 = _cimg_lanczos(t),
                     w3 = _cimg_lanczos(t - 1),
-                    w4 = _cimg_lanczos(t - 2);
-                  const Tfloat
-                    val2 = (Tfloat)*ptrs,
-                    val1 = ptrs>=ptrsmin?(Tfloat)*(ptrs - sxyz):val2,
-                    val0 = ptrs>ptrsmin?(Tfloat)*(ptrs - 2*sxyz):val1,
-                    val3 = ptrs<=ptrsmax?(Tfloat)*(ptrs + sxyz):val2,
-                    val4 = ptrs<ptrsmax?(Tfloat)*(ptrs + 2*sxyz):val3,
+                    w4 = _cimg_lanczos(t - 2),
+                    val2 = (double)*ptrs,
+                    val1 = ptrs>=ptrsmin?(double)*(ptrs - sxyz):val2,
+                    val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxyz):val1,
+                    val3 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val2,
+                    val4 = ptrs<ptrsmax?(double)*(ptrs + 2*sxyz):val3,
                     val = (val0*w0 + val1*w1 + val2*w2 + val3*w3 + val4*w4)/(w1 + w2 + w3 + w4);
                   *ptrd = (T)(val<vmin?vmin:val>vmax?vmax:val);
                   ptrd+=sxyz;
@@ -28702,11 +29075,11 @@ namespace cimg_library_suffixed {
     //! Permute axes order \newinstance.
     CImg<T> get_permute_axes(const char *const order) const {
       const T foo = (T)0;
-      return _get_permute_axes(order,foo);
+      return _permute_axes(order,foo);
     }
 
     template<typename t>
-    CImg<t> _get_permute_axes(const char *const permut, const t&) const {
+    CImg<t> _permute_axes(const char *const permut, const t&) const {
       if (is_empty() || !permut) return CImg<t>(*this,false);
       CImg<t> res;
       const T* ptrs = _data;
@@ -31035,26 +31408,41 @@ namespace cimg_library_suffixed {
       return get_correlate(kernel,boundary_conditions,is_normalized).move_to(*this);
     }
 
-    //! Correlate image by a kernel \newinstance.
     template<typename t>
     CImg<_cimg_Ttfloat> get_correlate(const CImg<t>& kernel, const unsigned int boundary_conditions=1,
                                       const bool is_normalized=false) const {
+      return _correlate(kernel,boundary_conditions,is_normalized,false);
+    }
+
+    //! Correlate image by a kernel \newinstance.
+    template<typename t>
+    CImg<_cimg_Ttfloat> _correlate(const CImg<t>& kernel, const unsigned int boundary_conditions,
+                                   const bool is_normalized, const bool is_convolution) const {
       if (is_empty() || !kernel) return *this;
       typedef _cimg_Ttfloat Ttfloat;
       CImg<Ttfloat> res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
       cimg_abort_init;
       if (boundary_conditions && kernel._width==kernel._height &&
           ((kernel._depth==1 && kernel._width<=5) || (kernel._depth==kernel._width && kernel._width<=3))) {
-        // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 kernel (with boundary_conditions=1)
+        // A special optimization is done for 2x2, 3x3, 4x4, 5x5, 2x2x2 and 3x3x3 kernel (with boundary_conditions=1).
+        CImg<t> _kernel;
+        if (is_convolution) { // Add empty column/row/slice to shift kernel center in case of convolution
+          const int dw = !(kernel.width()%2), dh = !(kernel.height()%2), dd = !(kernel.depth()%2);
+          if (dw || dh || dd)
+            kernel.get_resize(kernel.width() + dw,kernel.height() + dh,kernel.depth() + dd,-100,0,0).
+              move_to(_kernel);
+        }
+        if (!_kernel) _kernel = kernel.get_shared();
+
         Ttfloat *ptrd = res._data;
         CImg<T> I;
-        switch (kernel._depth) {
+        switch (_kernel._depth) {
         case 3 : {
           I.assign(27);
           cimg_forC(res,c) {
             cimg_abort_test();
             const CImg<T> _img = get_shared_channel(c%_spectrum);
-            const CImg<t> _K = kernel.get_shared_channel(c%kernel._spectrum);
+            const CImg<t> _K = _kernel.get_shared_channel(c%_kernel._spectrum);
             if (is_normalized) {
               const Ttfloat _M = (Ttfloat)_K.magnitude(2), M = _M*_M;
               cimg_for3x3x3(_img,x,y,z,0,I,T) {
@@ -31094,7 +31482,7 @@ namespace cimg_library_suffixed {
           cimg_forC(res,c) {
             cimg_abort_test();
             const CImg<T> _img = get_shared_channel(c%_spectrum);
-            const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+            const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
             if (is_normalized) {
               const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
               cimg_for2x2x2(_img,x,y,z,0,I,T) {
@@ -31116,13 +31504,13 @@ namespace cimg_library_suffixed {
         } break;
         default :
         case 1 :
-          switch (kernel._width) {
+          switch (_kernel._width) {
           case 6 : {
             I.assign(36);
             cimg_forC(res,c) {
               cimg_abort_test();
               const CImg<T> _img = get_shared_channel(c%_spectrum);
-              const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+              const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
               if (is_normalized) {
                 const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                 cimg_forZ(_img,z) cimg_for6x6(_img,x,y,z,0,I,T) {
@@ -31162,7 +31550,7 @@ namespace cimg_library_suffixed {
             cimg_forC(res,c) {
               cimg_abort_test();
               const CImg<T> _img = get_shared_channel(c%_spectrum);
-              const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+              const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
               if (is_normalized) {
                 const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                 cimg_forZ(_img,z) cimg_for5x5(_img,x,y,z,0,I,T) {
@@ -31194,7 +31582,7 @@ namespace cimg_library_suffixed {
             cimg_forC(res,c) {
               cimg_abort_test();
               const CImg<T> _img = get_shared_channel(c%_spectrum);
-              const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+              const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
               if (is_normalized) {
                 const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                 cimg_forZ(_img,z) cimg_for4x4(_img,x,y,z,0,I,T) {
@@ -31220,7 +31608,7 @@ namespace cimg_library_suffixed {
             cimg_forC(res,c) {
               cimg_abort_test();
               const CImg<T> _img = get_shared_channel(c%_spectrum);
-              const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+              const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
               if (is_normalized) {
                 const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                 cimg_forZ(_img,z) cimg_for3x3(_img,x,y,z,0,I,T) {
@@ -31242,7 +31630,7 @@ namespace cimg_library_suffixed {
             cimg_forC(res,c) {
               cimg_abort_test();
               const CImg<T> _img = get_shared_channel(c%_spectrum);
-              const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+              const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
               if (is_normalized) {
                 const Ttfloat _M = (Ttfloat)K.magnitude(2), M = _M*_M;
                 cimg_forZ(_img,z) cimg_for2x2(_img,x,y,z,0,I,T) {
@@ -31261,20 +31649,19 @@ namespace cimg_library_suffixed {
             else cimg_forC(res,c) {
                 cimg_abort_test();
                 const CImg<T> _img = get_shared_channel(c%_spectrum);
-                const CImg<t> K = kernel.get_shared_channel(c%kernel._spectrum);
+                const CImg<t> K = _kernel.get_shared_channel(c%_kernel._spectrum);
                 res.get_shared_channel(c).assign(_img)*=K[0];
               }
             break;
           }
         }
       } else { // Generic version for other kernels and boundary conditions.
-        const int
+        int
           mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2,
-          mx1 = mx2 - 1 + (kernel.width()%2), my1 = my2 - 1 + (kernel.height()%2), mz1 = mz2 - 1 + (kernel.depth()%2),
+          mx1 = kernel.width() - mx2 - 1, my1 = kernel.height() - my2 - 1, mz1 = kernel.depth() - mz2 - 1;
+        if (is_convolution) cimg::swap(mx1,mx2,my1,my2,mz1,mz2); // Shift kernel center in case of convolution
+        const int
           mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
-#if cimg_OS!=2
-        cimg_pragma_openmp(parallel for cimg_openmp_if(res._spectrum>=2)) // (Isn't stable on Windows)
-#endif
         cimg_forC(res,c) cimg_abort_try {
           cimg_abort_test();
           const CImg<T> _img = get_shared_channel(c%_spectrum);
@@ -31335,7 +31722,7 @@ namespace cimg_library_suffixed {
               } cimg_abort_catch2()
           } else { // Classical correlation.
             cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width*_height*_depth>=32768))
-            for (int z = mz1; z<mze; ++z)
+              for (int z = mz1; z<mze; ++z)
               for (int y = my1; y<mye; ++y)
                 for (int x = mx1; x<mxe; ++x) cimg_abort_try2 {
                   cimg_abort_test2();
@@ -31396,6 +31783,14 @@ namespace cimg_library_suffixed {
       return get_convolve(kernel,boundary_conditions,is_normalized).move_to(*this);
     }
 
+    //! Convolve image by a kernel \newinstance.
+    template<typename t>
+    CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& kernel, const unsigned int boundary_conditions=1,
+                                     const bool is_normalized=false) const {
+      return _correlate(CImg<t>(kernel._data,kernel.size(),1,1,1,true).get_mirror('x').
+                        resize(kernel,-1),boundary_conditions,is_normalized,true);
+    }
+
     //! Cumulate image values, optionally along specified axis.
     /**
        \param axis Cumulation axis. Set it to 0 to cumulate all values globally without taking axes into account.
@@ -31465,20 +31860,11 @@ namespace cimg_library_suffixed {
       return CImg<Tlong>(*this,false).cumulate(axes);
     }
 
-    //! Convolve image by a kernel \newinstance.
-    template<typename t>
-    CImg<_cimg_Ttfloat> get_convolve(const CImg<t>& kernel, const unsigned int boundary_conditions=1,
-                                     const bool is_normalized=false) const {
-      if (is_empty() || !kernel) return *this;
-      return get_correlate(CImg<t>(kernel._data,kernel.size(),1,1,1,true).get_mirror('x').
-                           resize(kernel,-1),boundary_conditions,is_normalized);
-    }
-
     //! Erode image by a structuring element.
     /**
        \param kernel Structuring element.
        \param boundary_conditions Boundary conditions.
-       \param is_real Do the erosion in real mode (\c true) rather than binary mode (\c false).
+       \param is_real Do the erosion in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false).
     **/
     template<typename t>
     CImg<T>& erode(const CImg<t>& kernel, const unsigned int boundary_conditions=1,
@@ -31497,12 +31883,9 @@ namespace cimg_library_suffixed {
       CImg<Tt> res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum));
       const int
         mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2,
-        mx1 = mx2 - 1 + (kernel.width()%2), my1 = my2 - 1 + (kernel.height()%2), mz1 = mz2 - 1 + (kernel.depth()%2),
+        mx1 = kernel.width() - mx2 - 1, my1 = kernel.height() - my2 - 1, mz1 = kernel.depth() - mz2 - 1,
         mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
       cimg_abort_init;
-#if cimg_OS!=2
-      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) // (Isn't stable on Windows)
-#endif
       cimg_forC(*this,c) cimg_abort_try {
         cimg_abort_test();
         const CImg<T> _img = get_shared_channel(c%_spectrum);
@@ -31517,7 +31900,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm) {
-                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
+                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                       const Tt cval = (Tt)(_img(x + xm,y + ym,z + zm) - mval);
                       if (cval<min_val) min_val = cval;
                     }
@@ -31532,7 +31915,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm) {
-                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
+                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                       const Tt cval = (Tt)(_img._atXYZ(x + xm,y + ym,z + zm) - mval);
                       if (cval<min_val) min_val = cval;
                     }
@@ -31548,7 +31931,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm) {
-                      const t mval = K(mx2 - xm,my2 - ym,mz2 - zm);
+                      const t mval = K(mx1 + xm,my1 + ym,mz1 + zm);
                       const Tt cval = (Tt)(_img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) - mval);
                       if (cval<min_val) min_val = cval;
                     }
@@ -31566,7 +31949,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm)
-                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
+                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                         const Tt cval = (Tt)_img(x + xm,y + ym,z + zm);
                         if (cval<min_val) min_val = cval;
                       }
@@ -31581,7 +31964,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm)
-                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
+                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                         const T cval = (Tt)_img._atXYZ(x + xm,y + ym,z + zm);
                         if (cval<min_val) min_val = cval;
                       }
@@ -31597,7 +31980,7 @@ namespace cimg_library_suffixed {
                 for (int zm = -mz1; zm<=mz2; ++zm)
                   for (int ym = -my1; ym<=my2; ++ym)
                     for (int xm = -mx1; xm<=mx2; ++xm)
-                      if (K(mx2 - xm,my2 - ym,mz2 - zm)) {
+                      if (K(mx1 + xm,my1 + ym,mz1 + zm)) {
                         const T cval = (Tt)_img.atXYZ(x + xm,y + ym,z + zm,0,(T)0);
                         if (cval<min_val) min_val = cval;
                       }
@@ -31619,7 +32002,7 @@ namespace cimg_library_suffixed {
     CImg<T>& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {
       if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;
       if (sx>1 && _width>1) { // Along X-axis.
-        const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
+        const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
         cimg_forYZC(*this,y,z,c) {
@@ -31659,7 +32042,7 @@ namespace cimg_library_suffixed {
       }
 
       if (sy>1 && _height>1) { // Along Y-axis.
-        const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,
+        const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
           s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
@@ -31701,7 +32084,7 @@ namespace cimg_library_suffixed {
       }
 
       if (sz>1 && _depth>1) { // Along Z-axis.
-        const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,
+        const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
           s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
@@ -31766,7 +32149,7 @@ namespace cimg_library_suffixed {
     /**
        \param kernel Structuring element.
        \param boundary_conditions Boundary conditions.
-       \param is_real Do the dilation in real mode (\c true) rather than binary mode (\c false).
+       \param is_real Do the dilation in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false).
     **/
     template<typename t>
     CImg<T>& dilate(const CImg<t>& kernel, const unsigned int boundary_conditions=1,
@@ -31783,13 +32166,10 @@ namespace cimg_library_suffixed {
       typedef _cimg_Tt Tt;
       CImg<Tt> res(_width,_height,_depth,_spectrum);
       const int
-        mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2,
-        mx1 = mx2 - 1 + (kernel.width()%2), my1 = my2 - 1 + (kernel.height()%2), mz1 = mz2 - 1 + (kernel.depth()%2),
+        mx1 = kernel.width()/2, my1 = kernel.height()/2, mz1 = kernel.depth()/2,
+        mx2 = kernel.width() - mx1 - 1, my2 = kernel.height() - my1 - 1, mz2 = kernel.depth() - mz1 - 1,
         mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2;
       cimg_abort_init;
-#if cimg_OS!=2
-      cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) // (Isn't stable on Windows)
-#endif
       cimg_forC(*this,c) cimg_abort_try {
         cimg_abort_test();
         const CImg<T> _img = get_shared_channel(c%_spectrum);
@@ -31905,7 +32285,7 @@ namespace cimg_library_suffixed {
     CImg<T>& dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) {
       if (is_empty() || (sx==1 && sy==1 && sz==1)) return *this;
       if (sx>1 && _width>1) { // Along X-axis.
-        const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
+        const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
         cimg_forYZC(*this,y,z,c) {
@@ -31946,7 +32326,7 @@ namespace cimg_library_suffixed {
       }
 
       if (sy>1 && _height>1) { // Along Y-axis.
-        const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
+        const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,
           s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
@@ -31988,7 +32368,7 @@ namespace cimg_library_suffixed {
       }
 
       if (sz>1 && _depth>1) { // Along Z-axis.
-        const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1,
+        const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1,
           s2 = _s2>L?L:_s2;
         CImg<T> buf(L);
         cimg_pragma_openmp(parallel for collapse(3) firstprivate(buf) if (size()>524288))
@@ -33570,7 +33950,7 @@ namespace cimg_library_suffixed {
       CImg<T> res(_width,_height,_depth,_spectrum);
       T *ptrd = res._data;
       cimg::unused(ptrd);
-      const int hl = (int)n/2, hr = hl - 1 + (int)n%2;
+      const int hr = (int)n/2, hl = n - hr - 1;
       if (res._depth!=1) { // 3d
         if (threshold>0)
           cimg_pragma_openmp(parallel for collapse(3) cimg_openmp_if(_width>=16 && _height*_depth*_spectrum>=4))
@@ -34668,9 +35048,9 @@ namespace cimg_library_suffixed {
                               const unsigned int nb_randoms,
                               const CImg<t1> &guide,
                               CImg<t2> &matching_score) const {
-      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
-                             nb_iterations,nb_randoms,
-                             guide,true,matching_score);
+      return _patchmatch(patch_image,patch_width,patch_height,patch_depth,
+                         nb_iterations,nb_randoms,
+                         guide,true,matching_score);
     }
 
     //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
@@ -34695,9 +35075,9 @@ namespace cimg_library_suffixed {
                               const unsigned int nb_iterations,
                               const unsigned int nb_randoms,
                               const CImg<t> &guide) const {
-      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
-                             nb_iterations,nb_randoms,
-                             guide,false,CImg<T>::empty());
+      return _patchmatch(patch_image,patch_width,patch_height,patch_depth,
+                         nb_iterations,nb_randoms,
+                         guide,false,CImg<T>::empty());
     }
 
     //! Compute correspondence map between two images, using the patch-match algorithm \overloading.
@@ -34718,22 +35098,22 @@ namespace cimg_library_suffixed {
                               const unsigned int patch_depth=1,
                               const unsigned int nb_iterations=5,
                               const unsigned int nb_randoms=5) const {
-      return _get_patchmatch(patch_image,patch_width,patch_height,patch_depth,
-                             nb_iterations,nb_randoms,
-                             CImg<T>::const_empty(),
-                             false,CImg<T>::empty());
+      return _patchmatch(patch_image,patch_width,patch_height,patch_depth,
+                         nb_iterations,nb_randoms,
+                         CImg<T>::const_empty(),
+                         false,CImg<T>::empty());
     }
 
     template<typename t1, typename t2>
-    CImg<intT> _get_patchmatch(const CImg<T>& patch_image,
-                               const unsigned int patch_width,
-                               const unsigned int patch_height,
-                               const unsigned int patch_depth,
-                               const unsigned int nb_iterations,
-                               const unsigned int nb_randoms,
-                               const CImg<t1> &guide,
-                               const bool is_matching_score,
-                               CImg<t2> &matching_score) const {
+    CImg<intT> _patchmatch(const CImg<T>& patch_image,
+                           const unsigned int patch_width,
+                           const unsigned int patch_height,
+                           const unsigned int patch_depth,
+                           const unsigned int nb_iterations,
+                           const unsigned int nb_randoms,
+                           const CImg<t1> &guide,
+                           const bool is_matching_score,
+                           CImg<t2> &matching_score) const {
       if (is_empty()) return CImg<intT>::const_empty();
       if (patch_image._spectrum!=_spectrum)
         throw CImgArgumentException(_cimg_instance
@@ -41389,12 +41769,11 @@ namespace cimg_library_suffixed {
                             const int x1, const int y1, const int z1, const int c1,
                             const T val, const float opacity=1) {
       if (is_empty()) return *this;
-      const bool bx = (x0<x1), by = (y0<y1), bz = (z0<z1), bc = (c0<c1);
       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,
-        nc0 = bc?c0:c1, nc1 = bc?c1:c0;
+        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
+        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0,
+        nz0 = z0<z1?z0:z1, nz1 = z0^z1^nz0,
+        nc0 = c0<c1?c0:c1, nc1 = c0^c1^nc0;
       const int
         lX = (1 + nx1 - nx0) + (nx1>=width()?width() - 1 - nx1:0) + (nx0<0?nx0:0),
         lY = (1 + ny1 - ny0) + (ny1>=height()?height() - 1 - ny1:0) + (ny0<0?ny0:0),
@@ -41491,10 +41870,9 @@ namespace cimg_library_suffixed {
       if (is_empty()) return *this;
       if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true);
       if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true);
-      const bool bx = (x0<x1), by = (y0<y1);
       const int
-        nx0 = bx?x0:x1, nx1 = bx?x1:x0,
-        ny0 = by?y0:y1, ny1 = by?y1:y0;
+        nx0 = x0<x1?x0:x1, nx1 = x0^x1^nx0,
+        ny0 = y0<y1?y0:y1, ny1 = y0^y1^ny0;
       if (ny1==ny0 + 1) return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
                       draw_line(nx1,ny1,nx0,ny1,color,opacity,pattern,false);
       return draw_line(nx0,ny0,nx1,ny0,color,opacity,pattern,true).
@@ -44642,7 +45020,7 @@ namespace cimg_library_suffixed {
     CImg<intT> get_select(CImgDisplay &disp,
 		          const unsigned int feature_type=2, unsigned int *const XYZ=0,
                           const bool exit_on_anykey=false) const {
-      return _get_select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
+      return _select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
     }
 
     //! Simple interface to select a shape from an image \newinstance.
@@ -44650,15 +45028,15 @@ namespace cimg_library_suffixed {
     			  const unsigned int feature_type=2, unsigned int *const XYZ=0,
                           const bool exit_on_anykey=false) const {
       CImgDisplay disp;
-      return _get_select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
+      return _select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false);
     }
 
-    CImg<intT> _get_select(CImgDisplay &disp, const char *const title,
-			   const unsigned int feature_type, unsigned int *const XYZ,
-			   const int origX, const int origY, const int origZ,
-                           const bool exit_on_anykey,
-                           const bool reset_view3d,
-                           const bool force_display_z_coord) const {
+    CImg<intT> _select(CImgDisplay &disp, const char *const title,
+                       const unsigned int feature_type, unsigned int *const XYZ,
+                       const int origX, const int origY, const int origZ,
+                       const bool exit_on_anykey,
+                       const bool reset_view3d,
+                       const bool force_display_z_coord) const {
       if (is_empty()) return CImg<intT>(1,feature_type==0?3:6,1,1,-1);
       if (!disp) {
         disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1);
@@ -45142,7 +45520,7 @@ namespace cimg_library_suffixed {
                 else cimg_snprintf(text,text._width," Point (%d,%d) = [ ",origX + (int)X,origY + (int)Y);
                 char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512;
                 for (unsigned int c = 0; c<_spectrum && ctext<ltext; ++c) {
-                  cimg_snprintf(ctext,text._width/2,cimg::type<T>::format(),
+                  cimg_snprintf(ctext,text._width/2,cimg::type<T>::format_s(),
                                 cimg::type<T>::format((*this)((int)X,(int)Y,(int)Z,c)));
                   ctext = text._data + std::strlen(text);
                   *(ctext++) = ' '; *ctext = 0;
@@ -45891,7 +46269,7 @@ namespace cimg_library_suffixed {
       if (header_size>40) cimg::fseek(nfile,header_size - 40,SEEK_CUR);
 
       const int
-        dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2?1:0)):(dx*bpp/8)),
+        dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2)):(dx*bpp/8)),
         align_bytes = (4 - dx_bytes%4)%4;
       const longT
         cimg_iobuffer = (longT)24*1024*1024,
@@ -48702,6 +49080,7 @@ namespace cimg_library_suffixed {
        \param display_stats Tells to compute and display image statistics.
     **/
     const CImg<T>& print(const char *const title=0, const bool display_stats=true) const {
+
       int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0;
       CImg<doubleT> st;
       if (!is_empty() && display_stats) {
@@ -48709,6 +49088,7 @@ namespace cimg_library_suffixed {
         xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7];
         xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11];
       }
+
       const ulongT siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1,
         mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1;
 
@@ -48719,7 +49099,7 @@ namespace cimg_library_suffixed {
                    cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal,
                    cimg::t_bold,cimg::t_normal,(void*)this,
                    cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum,
-                   mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)),
+                   (unsigned long)(mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20))),
                    mdisp==0?"b":(mdisp==1?"Kio":"Mio"),
                    cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin());
       if (_data)
@@ -48727,7 +49107,7 @@ namespace cimg_library_suffixed {
       else std::fprintf(cimg::output()," (%s) = [ ",_is_shared?"shared":"non-shared");
 
       if (!is_empty()) cimg_foroff(*this,off) {
-        std::fprintf(cimg::output(),cimg::type<T>::format(),cimg::type<T>::format(_data[off]));
+        std::fprintf(cimg::output(),"%g",(double)_data[off]);
         if (off!=siz1) std::fprintf(cimg::output(),"%s",off%_width==width1?" ; ":" ");
         if (off==7 && siz>16) { off = siz1 - 8; std::fprintf(cimg::output(),"... "); }
       }
@@ -48811,7 +49191,6 @@ namespace cimg_library_suffixed {
         } else zoom = get_crop(x0,y0,z0,x1,y1,z1);
 
         const CImg<T>& visu = zoom?zoom:*this;
-
         const unsigned int
           dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0,
           tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U);
@@ -48842,7 +49221,7 @@ namespace cimg_library_suffixed {
         }
 
         disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y;
-        const CImg<intT> selection = visu._get_select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1);
+        const CImg<intT> selection = visu._select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1);
         old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y;
         is_first_select = false;
 
@@ -49920,7 +50299,7 @@ namespace cimg_library_suffixed {
       std::fprintf(nfile,"%u %u %u %u\n",_width,_height,_depth,_spectrum);
       const T* ptrs = _data;
       cimg_forYZC(*this,y,z,c) {
-        cimg_forX(*this,x) std::fprintf(nfile,"%.16g ",(double)*(ptrs++));
+        cimg_forX(*this,x) std::fprintf(nfile,"%.17g ",(double)*(ptrs++));
         std::fputc('\n',nfile);
       }
       if (!file) cimg::fclose(nfile);
@@ -49997,7 +50376,7 @@ namespace cimg_library_suffixed {
       std::FILE *const nfile = file?file:cimg::fopen(filename,"w");
       const T* ptrs = _data;
       cimg_forYZC(*this,y,z,c) {
-        cimg_forX(*this,x) std::fprintf(nfile,"%.16g%s",(double)*(ptrs++),(x==width() - 1)?"":",");
+        cimg_forX(*this,x) std::fprintf(nfile,"%.17g%s",(double)*(ptrs++),(x==width() - 1)?"":",");
         std::fputc('\n',nfile);
       }
       if (!file) cimg::fclose(nfile);
@@ -54370,7 +54749,7 @@ namespace cimg_library_suffixed {
     CImg<intT> get_select(CImgDisplay &disp, const bool feature_type=true,
                           const char axis='x', const float align=0,
                           const bool exit_on_anykey=false) const {
-      return _get_select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false);
+      return _select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false);
     }
 
     //! Display a simple interactive interface to select images or sublists.
@@ -54385,13 +54764,13 @@ namespace cimg_library_suffixed {
                           const char axis='x', const float align=0,
                           const bool exit_on_anykey=false) const {
       CImgDisplay disp;
-      return _get_select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false);
+      return _select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false);
     }
 
-    CImg<intT> _get_select(CImgDisplay &disp, const char *const title, const bool feature_type,
-                           const char axis, const float align, const bool exit_on_anykey,
-                           const unsigned int orig, const bool resize_disp,
-                           const bool exit_on_rightbutton, const bool exit_on_wheel) const {
+    CImg<intT> _select(CImgDisplay &disp, const char *const title, const bool feature_type,
+                       const char axis, const float align, const bool exit_on_anykey,
+                       const unsigned int orig, const bool resize_disp,
+                       const bool exit_on_rightbutton, const bool exit_on_wheel) const {
       if (is_empty())
         throw CImgInstanceException(_cimglist_instance
                                     "select(): Empty instance.",
@@ -54841,7 +55220,7 @@ namespace cimg_library_suffixed {
       CImg<charT> tmp(256), str_pixeltype(256), str_endian(256);
       *tmp = *str_pixeltype = *str_endian = 0;
       unsigned int j, N = 0, W, H, D, C;
-      ulongT csiz;
+      unsigned long csiz;
       int i, err;
       do {
         j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0;
@@ -55890,7 +56269,7 @@ namespace cimg_library_suffixed {
       } else {
         bool disp_resize = !is_first_call;
         while (!disp.is_closed() && !is_exit) {
-          const CImg<intT> s = _get_select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true);
+          const CImg<intT> s = _select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true);
           disp_resize = true;
           if (s[0]<0 && !disp.wheel()) { // No selections done.
             if (disp.button()&2) { disp.flush(); break; }
@@ -58057,7 +58436,7 @@ namespace cimg {
   inline const char *strbuffersize(const cimg_ulong size) {
     static CImg<char> res(256);
     cimg::mutex(5);
-    if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",size,size>1?"s":"");
+    if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",(unsigned long)size,size>1?"s":"");
     else if (size<1024*1024LU) { const float nsize = size/1024.0f; cimg_snprintf(res,res._width,"%.1f Kio",nsize); }
     else if (size<1024*1024*1024LU) {
       const float nsize = size/(1024*1024.0f); cimg_snprintf(res,res._width,"%.1f Mio",nsize);
diff --git a/examples/CImg_demo.cpp b/examples/CImg_demo.cpp
index 08b77ff..b9f4218 100644
--- a/examples/CImg_demo.cpp
+++ b/examples/CImg_demo.cpp
@@ -868,7 +868,7 @@ void* item_blobs_editor() {
           for (unsigned int x = x0; x<=x1; ++x) {
             float dist = dx*dx + dy*dy;
             if (dist<precision) {
-              const float val = (float)exp(-dist/sigma2);
+              const float val = (float)std::exp(-dist/sigma2);
               *ptr+=(unsigned int)(val*col1);
               *(ptr + wh)+=(unsigned int)(val*col2);
               *(ptr + 2*wh)+=(unsigned int)(val*col3);
diff --git a/examples/edge_explorer2d.cpp b/examples/edge_explorer2d.cpp
index b8188f8..7e620c4 100644
--- a/examples/edge_explorer2d.cpp
+++ b/examples/edge_explorer2d.cpp
@@ -133,13 +133,13 @@ int main(int argc, char** argv) {
           // s corresponds to the x-ordinate of the pixel while t corresponds to the y-ordinate.
           if ( 1 <= s && s <= visu_bw.width() - 1 && 1 <= t && t <=visu_bw.height() - 1) { // if - good points
             double
-              Gs = grad[0](s,t),                  //
-              Gt = grad[1](s,t),                               //  The actual pixel is (s,t)
-              Gst = cimg::abs(Gs) + cimg::abs(Gt),    //
+              Gs = grad[0](s,t),                    //
+              Gt = grad[1](s,t),                    //  The actual pixel is (s,t)
+              Gst = cimg::abs(Gs) + cimg::abs(Gt),  //
               // ^-- For efficient computation we observe that |Gs|+ |Gt| ~=~ sqrt( Gs^2 + Gt^2)
               Gr, Gur, Gu, Gul, Gl, Gdl, Gd, Gdr;
             // ^-- right, up right, up, up left, left, down left, down, down right.
-            double theta = std::atan2(Gt,Gs) + pi; // theta is from the interval [0,Pi]
+            double theta = std::atan2(std::max(1e-8,Gt),Gs) + pi; // theta is from the interval [0,Pi]
             switch(mode) {
             case 1: // Hysterese is applied
               if (Gst>=thresH) { edge.draw_point(s,t,black); }
diff --git a/html/header.html b/html/header.html
index af71d0d..73b0d5f 100644
--- a/html/header.html
+++ b/html/header.html
@@ -47,8 +47,8 @@
           </center>
           <center><font size="-1" color="#777777">
               Latest stable version: <b><a href="http://cimg.eu/files">1.7.8</a></b>
-              <!--    -    -->
-              <!-- Development snapshot: <b><a href="http://cimg.eu/files">1.7.9_pre</a></b> -->
+                 -   
+              Development snapshot: <b><a href="http://cimg.eu/files">1.7.9_pre</a></b>
           </font></center>
       </td></tr>
       <tr bgcolor="#FFFFFF"><td><hr noshade size="1" style="border-top: 1px solid #ccc;"/></td></tr>
diff --git a/html/header_reference.html b/html/header_reference.html
index 7717d96..a13c005 100644
--- a/html/header_reference.html
+++ b/html/header_reference.html
@@ -46,8 +46,8 @@
           </center>
           <center><font size="-1" color="#777777">
               Latest stable version: <b><a href="http://cimg.eu/files">1.7.8</a></b>
-              <!--    -    -->
-              <!-- Development snapshot: <b><a href="http://cimg.eu/files">1.7.8_pre</a></b> -->
+                 -   
+              Development snapshot: <b><a href="http://cimg.eu/files">1.7.8_pre</a></b>
           </font></center>
       </td></tr>
       <tr bgcolor="#FFFFFF"><td><hr noshade size="1" style="border-top: 1px solid #ccc;"/></td></tr>
diff --git a/html/img/CImgLogo2.jpg b/html/img/CImgLogo2.jpg
index a8586b2..0a6927b 100644
Binary files a/html/img/CImgLogo2.jpg and b/html/img/CImgLogo2.jpg differ
diff --git a/html/img/postcard65.jpg b/html/img/postcard65.jpg
new file mode 100644
index 0000000..a5eef4e
Binary files /dev/null and b/html/img/postcard65.jpg differ
diff --git a/html/index.shtml b/html/index.shtml
index 48cecdf..332107d 100644
--- a/html/index.shtml
+++ b/html/index.shtml
@@ -250,7 +250,7 @@
       or parts of the <a href="reference/index.html">documentation</a>.</li>
     <li>If you just want to say you've been happy with the library, you can send me a postcard from your place, to the following address : <br/>
       <i>David Tschumperlé, GREYC (UMR CNRS 6072), Equipe IMAGE, 6 Bd du Maréchal Juin, 14050 Caen Cedex, FRANCE.</i><br/><br/>
-      63 postcards received yet (I still have empty space on my wall ! :) ), from :<br/><br/>
+      65 postcards received yet (I still have empty space on my wall ! :) ), from :<br/><br/>
       <ul>
         <li><a href="img/postcard1.jpg" onclick="NewWindow(this.href,'name','420','320','yes');return false;">
             Comissao Nacional de Energia Nuclear, Rio de Janeiro, Brazil.</a></li>
@@ -378,6 +378,9 @@
             Konstanz/Germany, from Sébastien Fourey.</a></li>
         <li><a href="img/postcard64.jpg" onclick="NewWindow(this.href,'name','320','420','yes');return false;">
             Bilbao/Spain, from Patrick Wauters.</a></li>
+        <li><a href="img/postcard65.jpg" onclick="NewWindow(this.href,'name','420','320','yes');return false;">
+            Haldern/Germany, from Volker Doebel.</a></li>
+
         <br/><br/></li>
     </ul></li>
   </ul>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/cimg.git



More information about the debian-science-commits mailing list